diff --git a/engine/core/src/utils/gameObjectList.zig b/engine/core/src/utils/gameObjectList.zig index 4dad885..535a000 100644 --- a/engine/core/src/utils/gameObjectList.zig +++ b/engine/core/src/utils/gameObjectList.zig @@ -14,6 +14,7 @@ pub const GameObjectInterfaceVTable = struct { destroy: *const fn (*anyopaque) void, tick: ?*const fn (*anyopaque, f64) void, getEntity: ?*const fn (*anyopaque) core.Entity, + objectName: []const u8 = "UnknownObject", }; pub const GameObjectData = struct { @@ -40,6 +41,7 @@ pub const GameObjectInterface = struct { pub const GameObjectList = struct { allocator: std.mem.Allocator, + // slots might be better? allow for stable indexes? objects: std.ArrayListUnmanaged(GameObjectInterface) = .{}, pub fn create(allocator: std.mem.Allocator) !*@This() { @@ -83,6 +85,7 @@ pub const GameObjectList = struct { pub const VTable = GameObjectInterfaceVTable{ .tick = if (@hasDecl(T, "tick")) w_tick else null, .getEntity = if (@hasDecl(T, "getEntity")) w_getEntity else null, + .objectName = @typeName(T), .destroy = w_destroy, }; }; diff --git a/engine/imgui/src/sgpu/backend_impl.zig b/engine/imgui/src/sgpu/backend_impl.zig index 5027319..a4b02c3 100644 --- a/engine/imgui/src/sgpu/backend_impl.zig +++ b/engine/imgui/src/sgpu/backend_impl.zig @@ -5,8 +5,6 @@ pub const Impl = struct { drawData: [*c]ig.DrawData = undefined, rendererDebug: bool = true, - dtAverage: f64 = 0.0, - pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); pub const Settings = struct { @@ -76,29 +74,8 @@ pub const Impl = struct { pub fn preTick(self: *@This(), dt: f64) core.EngineDataEventError!void { c.Imgui_SDL3_NewFrame(); c.igNewFrame(); - - core.rollingAverage(&self.dtAverage, dt, 50); - - if (ig.begin("renderer debug", &self.rendererDebug, .{})) { - _ = ig.sliderFloat("directional light yaw", &rend.context().directionalLightYaw, 0, 360, null, .{}); - _ = ig.sliderFloat("skyboxLevel", &rend.context().skyboxSystem.brightnessFactor, 0, 10, null, .{}); - _ = ig.sliderFloat("lightLevel", &rend.context().lightPower, 0, 100, null, .{}); - _ = ig.sliderFloat("ortho near", &rend.context().shadowOrthoNear, 0, 200, null, .{}); - _ = ig.sliderFloat("ortho far", &rend.context().shadowOrthoFar, 0, 6000, null, .{}); - if (self.dtAverage > 0.000001) { - ig.textFmt("frameTime: {d:.2}ms ({d:.2}fps)", .{ self.dtAverage * 1000, @as(u32, @intFromFloat(1 / self.dtAverage)) }) catch return error.UnknownStatePanic; - } - - ig.textFmt("SSAO settings: ", .{}) catch unreachable; - - const ssao = rend.context().ssaoSystem; - _ = ig.sliderFloat("radius", &ssao.radius, 0.1, 1.0, null, .{}); - _ = ig.sliderFloat("bias", &ssao.bias, 0.0025, 1.0, null, .{}); - - _ = ig.checkbox("enable SSAO", &ssao.enable); - - ig.end(); - } + _ = self; + _ = dt; } // renderer plugin diff --git a/engine/physics/src/physicsCollider.zig b/engine/physics/src/physicsCollider.zig index 31f47e6..6db4a03 100644 --- a/engine/physics/src/physicsCollider.zig +++ b/engine/physics/src/physicsCollider.zig @@ -31,7 +31,7 @@ pub const PhysicsCollider = struct { settings.shape = shape.shape; - const scene = self.entity.get(core.Scene).?; + const scene = self.entity.fetch(core.Scene).?; const p = scene.getPosition(); // core.engine_log("setting up collider shape {any}", .{p}); settings.position = .{ p.x, p.y, p.z, 1.0 }; diff --git a/engine/rend/src/rend.zig b/engine/rend/src/rend.zig index a6e6a6e..21b5d19 100644 --- a/engine/rend/src/rend.zig +++ b/engine/rend/src/rend.zig @@ -31,6 +31,7 @@ pub const createRendererObject = renderer.createRendererObject; pub const registerRendererObject = renderer.registerRendererObject; pub const getTexture = renderer.getTexture; +pub const textureExists = renderer.textureExists; pub const texture = @import("texture/texture.zig"); pub const Texture = texture.Texture; @@ -62,3 +63,7 @@ pub fn shutdown_module(allocator: std.mem.Allocator) void { _ = allocator; renderer.shutdown(); } + +pub fn getMeshPool() *MeshPool { + return context().meshPool; +} diff --git a/engine/rend/src/sgpu/DebugDrawSystem.zig b/engine/rend/src/sgpu/DebugDrawSystem.zig index 07288b9..c2cbe59 100644 --- a/engine/rend/src/sgpu/DebugDrawSystem.zig +++ b/engine/rend/src/sgpu/DebugDrawSystem.zig @@ -114,7 +114,7 @@ pub fn onUpload(p: *anyopaque, copyPass: *gpu.GPUCopyPass) void { .buffer = self.ssbo, .offset = 0, .size = @intCast(count * @sizeOf(debug_vert.Scene)), - }, true); + }, false); } } diff --git a/engine/rend/src/sgpu/TextureList.zig b/engine/rend/src/sgpu/TextureList.zig index b118208..2634ff8 100644 --- a/engine/rend/src/sgpu/TextureList.zig +++ b/engine/rend/src/sgpu/TextureList.zig @@ -13,6 +13,7 @@ allocator: std.mem.Allocator, device: *gpu.GPUDevice = undefined, map: std.AutoHashMapUnmanaged(u32, *Texture) = .{}, +requestMap: std.AutoHashMapUnmanaged(u32, bool) = .{}, pub fn create(allocator: std.mem.Allocator) !*@This() { const self = try allocator.create(@This()); @@ -33,6 +34,8 @@ pub fn loadAsset(self: *@This(), assetRef: assets.AssetRef, propertiesBag: ?asse var name = assetRef.name; core.engine_log("loading texture {s}", .{name.utf8()}); if (propertiesBag) |bag| { + self.requestMap.put(self.allocator, name.handle(), true) catch return error.UnableToLoad; // its always true in here. + var installed: *Texture = undefined; if (bag.textureCube) { const pathList = bag.textureList.?; @@ -235,6 +238,7 @@ pub fn destroy(self: *@This()) void { while (iter.next()) |x| { self.allocator.destroy(x.*); } + self.requestMap.deinit(self.allocator); self.map.deinit(self.allocator); self.allocator.destroy(self); } diff --git a/engine/rend/src/sgpu/mesh-pool.zig b/engine/rend/src/sgpu/mesh-pool.zig index ad89fa8..736c1b8 100644 --- a/engine/rend/src/sgpu/mesh-pool.zig +++ b/engine/rend/src/sgpu/mesh-pool.zig @@ -2,6 +2,8 @@ pub const MeshPool = struct { allocator: std.mem.Allocator, meshMap: std.AutoHashMapUnmanaged(u32, rend.IndexedMesh) = .{}, + invalidations: std.AutoHashMapUnmanaged(u32, rend.IndexedMesh) = .{}, + indexSpans: core.MergedSpans, vertexSpans: core.MergedSpans, @@ -49,6 +51,22 @@ pub const MeshPool = struct { return self; } + pub fn clearInvalidations(self: *@This()) void { + var iter = self.invalidations.iterator(); + while (iter.next()) |n| { + const invalidate = n.value_ptr; + _ = invalidate; + // self.indexSpans.removeSpan(invalidate.index); + // self.vertexSpans.removeSpan(invalidate.vertex); + } + + self.invalidations.clearRetainingCapacity(); + } + + pub fn isMeshInvalidated(self: @This(), name: *core.Name) bool { + return self.invalidations.contains(name.handle()); + } + pub fn onUploadCleanup(p: *anyopaque) void { const self: *@This() = @ptrCast(@alignCast(p)); @@ -71,6 +89,10 @@ pub const MeshPool = struct { var name = new.name; core.engine_log("uploading mesh => {s}", .{name.utf8()}); + if (self.installedMeshes.get(name.handle())) |installed| { + try self.invalidations.put(self.allocator, name.handle(), installed); + } + const indexSpan = try self.addTransfer(copyPass, self.indexBuffer, u32, &self.indexSpans, new.indices); const vertexSpan = try self.addTransfer(copyPass, self.vertexBuffer, meshes.MeshVertex, &self.vertexSpans, new.vertices); @@ -143,6 +165,8 @@ pub const MeshPool = struct { pub fn destroy(p: *anyopaque) void { const self: *@This() = @ptrCast(@alignCast(p)); + self.clearInvalidations(); + self.invalidations.deinit(self.allocator); self.device.releaseGPUBuffer(self.indexBuffer); self.device.releaseGPUBuffer(self.vertexBuffer); diff --git a/engine/rend/src/sgpu/renderer.zig b/engine/rend/src/sgpu/renderer.zig index 62d8fb2..59241a0 100644 --- a/engine/rend/src/sgpu/renderer.zig +++ b/engine/rend/src/sgpu/renderer.zig @@ -673,7 +673,7 @@ pub const Renderer = struct { for (0..uploadCount) |i| { const component = &container.dense.items[i].value; - if (component.mesh == null) { + if (component.mesh == null or self.meshPool.isMeshInvalidated(&component.meshName)) { component.updateMesh(); } @@ -682,6 +682,8 @@ pub const Renderer = struct { } } + self.meshPool.clearInvalidations(); + for (self.preDraws.items) |interface| { interface.func(interface.ptr, self.state.cmd.?); } @@ -1007,6 +1009,11 @@ pub const RendererState = struct { normalTarget: *gpu.GPUTexture = undefined, }; +pub fn textureExists(name: []const u8) bool { + var n = core.MakeName(name); + return gRenderer.textureList.requestMap.contains(n.handle()); +} + pub const CustomMeshRenderFunc = *const fn (?*anyopaque) void; pub const GPUTextureType = gpu.GPUTexture; diff --git a/extras/bsp/build.zig b/extras/bsp/build.zig new file mode 100644 index 0000000..9204611 --- /dev/null +++ b/extras/bsp/build.zig @@ -0,0 +1,17 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const mod = b.addModule("bsp", .{ + .target = target, + .optimize = optimize, + .root_source_file = b.path("src/bsp.zig"), + }); + + { + const dep = b.dependency("Backlog", .{ .target = target, .optimize = optimize }); + mod.addImport("Backlog", dep.module("Backlog")); + } +} diff --git a/extras/bsp/build.zig.zon b/extras/bsp/build.zig.zon new file mode 100644 index 0000000..ee0cc3e --- /dev/null +++ b/extras/bsp/build.zig.zon @@ -0,0 +1,11 @@ +.{ + .name = .bsp, + .version = "0.0.0", + .dependencies = .{ + .Backlog = .{ .path = "../../" }, + }, + .paths = .{ + "", + }, + .fingerprint = 0xe0059d559d550fd0, +} diff --git a/extras/bsp/src/QuakeMap.zig b/extras/bsp/src/QuakeMap.zig new file mode 100644 index 0000000..52e920b --- /dev/null +++ b/extras/bsp/src/QuakeMap.zig @@ -0,0 +1,417 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const TokenIterator = std.mem.TokenIterator; +pub const za = @import("zalgebra/main.zig"); +pub const Vec3 = za.Vec3; +pub const Vec3d = za.Vec3_f64; +const core = @import("Backlog").core; +const logger = std.log.scoped(.quakemap); + +const QuakeMap = @This(); + +worldspawn: Entity, +entities: std.ArrayList(Entity), +// uniqueMaterials: std.StringHashMap(u32), // counts for the number +// of times a material is used. + +pub const ErrorInfo = struct { + line_number: usize, +}; + +pub fn deinit(self: *@This()) void { + for (self.entities.items) |*entity| { + entity.deinit(); + } + self.worldspawn.deinit(); + self.entities.deinit(); +} + +pub fn read(allocator: Allocator, data: []const u8, error_info: *ErrorInfo) !QuakeMap { + var worldspawn: ?Entity = null; + var entities = std.ArrayList(Entity).init(allocator); + var iter = std.mem.tokenizeAny(u8, data, "\r\n"); + error_info.line_number = 0; + while (iter.next()) |line| { + error_info.line_number += 1; + switch (line[0]) { + '/' => continue, + '{' => { + const entity = try readEntity(allocator, &iter, error_info); + if (std.mem.eql(u8, entity.classname, "worldspawn")) { + worldspawn = entity; + } else { + try entities.append(entity); + } + }, + else => { + std.debug.print("error in line: {d} {s}\n", .{ error_info.line_number, line }); + return error.UnexpectedToken; + }, + } + } + + return .{ + .worldspawn = worldspawn orelse return error.WorldSpawnNotFound, + .entities = entities, + }; +} + +const Property = struct { + key: []const u8, + value: []const u8, +}; + +pub const Entity = struct { + classname: []const u8, + spawnflags: u32, + properties: std.ArrayList(Property), + solids: std.ArrayList(Solid), + + pub fn deinit(self: *@This()) void { + for (self.solids.items) |*solid| { + solid.faces.deinit(); + } + self.properties.deinit(); + } + + pub fn init(allocator: Allocator) Entity { + return .{ + .classname = &.{}, + .spawnflags = 0, + .properties = std.ArrayList(Property).init(allocator), + .solids = std.ArrayList(Solid).init(allocator), + }; + } + + fn indexOfProperty(self: Entity, key: []const u8) ?usize { + for (self.properties.items, 0..) |property, i| { + if (std.mem.eql(u8, property.key, key)) { + return i; + } + } + return null; + } + + pub fn hasProperty(self: Entity, key: []const u8) bool { + return self.indexOfProperty(key) != null; + } + + pub fn getStringProperty(self: Entity, key: []const u8) ![]const u8 { + const i = self.indexOfProperty(key) orelse return error.NotFound; + return self.properties.items[i].value; + } + + pub fn getIntProperty(self: Entity, key: []const u8) !i32 { + const string = try self.getStringProperty(key); + return try parseInt(string); + } + + pub fn getFloatProperty(self: Entity, key: []const u8) !f32 { + const string = try self.getStringProperty(key); + return try parseFloat(string); + } + + pub fn getVec3Property(self: Entity, key: []const u8) !Vec3 { + const string = try self.getStringProperty(key); + var it = std.mem.tokenizeScalar(u8, string, ' '); + var vec3: Vec3 = undefined; + for (0..3) |i| { + vec3.data[i] = try parseFloat(it.next() orelse return error.ExpectedFloat); + } + return vec3; + } +}; + +pub const Solid = struct { + faces: std.ArrayList(Face), + + fn init(allocator: Allocator) Solid { + return .{ .faces = std.ArrayList(Face).init(allocator) }; + } + + fn computeVertices(self: *Solid) !void { + const allocator = self.faces.allocator; + var buffer: [64]Vec3d = undefined; + var vertices = std.ArrayListUnmanaged(Vec3d).initBuffer(buffer[0..32]); + var clipped = std.ArrayListUnmanaged(Vec3d).initBuffer(buffer[32..64]); + for (self.faces.items, 0..) |*face, i| { + const quad = face.plane.makeQuadWithRadius(1000000.0); + vertices.clearRetainingCapacity(); + vertices.appendSliceAssumeCapacity(&quad); + // clip with other planes + for (self.faces.items, 0..) |clip_face, j| { + if (j == i) continue; + clipped.clearRetainingCapacity(); + try clip(vertices, clip_face.plane, &clipped); + if (clipped.items.len < 3) return error.DegenerateFace; + std.mem.swap(std.ArrayListUnmanaged(Vec3d), &vertices, &clipped); + } + face.vertices = try allocator.dupe(Vec3d, vertices.items); + } + } + + fn clip(vertices: std.ArrayListUnmanaged(Vec3d), clip_plane: Plane, clipped: *std.ArrayListUnmanaged(Vec3d)) !void { + const epsilon = 0.0001; + + var buffer: [32]f64 = undefined; + var distances = std.ArrayListUnmanaged(f64).initBuffer(&buffer); + var cb: usize = 0; + var cf: usize = 0; + for (vertices.items) |vertex| { + var distance = clip_plane.normal.dot(vertex) + clip_plane.d; + if (distance < -epsilon) { + cb += 1; + } else if (distance > epsilon) { + cf += 1; + } else { + distance = 0; + } + distances.appendAssumeCapacity(distance); + } + + if (cb == 0 and cf == 0) { + // co-planar + return; + } else if (cb == 0) { + // all vertices in front + return; + } else if (cf == 0) { + // all vertices in back; + // keep + clipped.appendSliceAssumeCapacity(vertices.items); + return; + } + + for (vertices.items, 0..) |s, i| { + const j = (i + 1) % vertices.items.len; + + const e = vertices.items[j]; + const sd = distances.items[i]; + const ed = distances.items[j]; + if (sd <= 0) clipped.appendAssumeCapacity(s); // back + + if ((sd < 0 and ed > 0) or (ed < 0 and sd > 0)) { + const t = sd / (sd - ed); + var intersect = Vec3d.lerp(s, e, t); + // use plane's distance from origin, if plane's normal is a unit vector + if (clip_plane.normal.x() == 1) intersect.data[0] = -clip_plane.d; + if (clip_plane.normal.x() == -1) intersect.data[0] = clip_plane.d; + if (clip_plane.normal.y() == 1) intersect.data[1] = -clip_plane.d; + if (clip_plane.normal.y() == -1) intersect.data[1] = clip_plane.d; + if (clip_plane.normal.z() == 1) intersect.data[2] = -clip_plane.d; + if (clip_plane.normal.z() == -1) intersect.data[2] = clip_plane.d; + clipped.appendAssumeCapacity(intersect); + } + } + } +}; + +fn closestAxis(v: Vec3d) Vec3d { + if (@abs(v.x()) >= @abs(v.y()) and @abs(v.x()) >= @abs(v.z())) return Vec3d.right(); // 1 0 0 + if (@abs(v.y()) >= @abs(v.z())) return Vec3d.up(); // 0 1 0 + return Vec3d.forward(); // 0 0 1 +} + +pub const Face = struct { + plane: Plane, + texture_name: []const u8, + u_axis: Vec3, + v_axis: Vec3, + shift_x: f32, + shift_y: f32, + rotation: f32, + scale_x: f32, + scale_y: f32, + uv_direction: Vec3, + + vertices: []Vec3d, +}; + +const Plane = struct { + normal: Vec3d, + d: f64, + + fn initFromVertices(v0: Vec3d, v1: Vec3d, v2: Vec3d) Plane { + const v0v1 = v1.sub(v0); + const v0v2 = v2.sub(v0); + const normal = Vec3d.cross(v0v1, v0v2).norm(); + const length = normal.dot(v0); + return .{ .normal = normal, .d = -length }; + } + + fn makeQuadWithRadius(self: Plane, radius: f32) [4]Vec3d { + const direction = closestAxis(self.normal); + var up = if (direction.z() == 1) Vec3d.right() else Vec3d.new(0, 0, -1); + const upv = up.dot(self.normal); + up = up.sub(self.normal.scale(upv)).norm(); + var right = up.cross(self.normal); + + up = up.scale(radius); + right = right.scale(radius); + + const origin = self.normal.scale(-self.d); + return .{ + origin.sub(right).sub(up), + origin.add(right).sub(up), + origin.add(right).add(up), + origin.sub(right).add(up), + }; + } +}; + +fn readEntity(allocator: Allocator, iter: *TokenIterator(u8, .any), error_info: *ErrorInfo) !Entity { + var entity = Entity.init(allocator); + while (iter.next()) |line| { + error_info.line_number += 1; + switch (line[0]) { + '/' => continue, + '"' => { + const property = try readProperty(line); + if (std.mem.eql(u8, property.key, "classname")) { + entity.classname = property.value; + } else if (std.mem.eql(u8, property.key, "spawnflags")) { + entity.spawnflags = try std.fmt.parseInt(u32, property.value, 10); + } else { + try entity.properties.append(property); + } + }, + '{' => try entity.solids.append(try readSolid(allocator, iter, error_info)), + '}' => break, + else => { + std.debug.print("error in line: {s}\n", .{line}); + return error.UnexpectedToken; + }, + } + } + return entity; +} + +fn readProperty(line: []const u8) !Property { + var property: Property = undefined; + var iter = std.mem.tokenizeScalar(u8, line, '"'); + property.key = try readSymbol(&iter); + if (!std.mem.eql(u8, iter.next() orelse return error.UnexpectedEof, " ")) return error.ExpectedSpace; + property.value = try readSymbol(&iter); + return property; +} + +fn readSolid(allocator: Allocator, iter: *TokenIterator(u8, .any), error_info: *ErrorInfo) !Solid { + var solid = Solid.init(allocator); + while (iter.next()) |line| { + error_info.line_number += 1; + switch (line[0]) { + '/' => continue, + '(' => try solid.faces.append(try readFace(line)), + '}' => break, + + else => { + std.debug.print("error in line: {s}\n", .{line}); + return error.UnexpectedToken; + }, + } + } + try solid.computeVertices(); + return solid; +} + +pub fn calculateRotatedUV(face: Face, u_axis: *Vec3, v_axis: *Vec3) void { + const scaled_u_axis = face.u_axis.scale(1.0 / face.scale_x); + const scaled_v_axis = face.v_axis.scale(1.0 / face.scale_y); + + const u_mat = za.Mat4.fromTranslate(scaled_u_axis); + const v_mat = za.Mat4.fromTranslate(scaled_v_axis); + + const rotation = za.Mat4.fromRotation(face.rotation, face.uv_direction); + u_axis.* = rotation.mul(u_mat).extractTranslation(); + v_axis.* = rotation.mul(v_mat).extractTranslation(); +} + +fn readFace(line: []const u8) !Face { + var face: Face = undefined; + var iter = std.mem.tokenizeScalar(u8, line, ' '); + const v0 = try readPoint(&iter); + const v1 = try readPoint(&iter); + const v2 = try readPoint(&iter); + // map planes are clockwise, flip them around when computing the plane to get a counter-clockwise plane + face.plane = Plane.initFromVertices(v2, v1, v0); + const closestNormal = closestAxis(face.plane.normal); + + face.uv_direction.data = .{ + @floatCast(closestNormal.data[0]), + @floatCast(closestNormal.data[1]), + @floatCast(closestNormal.data[2]), + }; + + face.u_axis = if (closestNormal.x() == 1) Vec3.new(0, 1, 0) else Vec3.new(1, 0, 0); + face.v_axis = if (closestNormal.z() == 1) Vec3.new(0, -1, 0) else Vec3.new(0, 0, -1); + face.texture_name = try readSymbol(&iter); + face.shift_x = try readDecimal(&iter); + face.shift_y = try readDecimal(&iter); + face.rotation = core.radians(try readDecimal(&iter)); + face.scale_x = try readDecimal(&iter); + face.scale_y = try readDecimal(&iter); + return face; +} + +fn readPoint(iter: *TokenIterator(u8, .scalar)) !Vec3d { + var point: Vec3d = undefined; + if (!std.mem.eql(u8, iter.next() orelse return error.UnexpectedEof, "(")) return error.ExpectedOpenParanthesis; + point.data[0] = try readDecimal(iter); + point.data[1] = try readDecimal(iter); + point.data[2] = try readDecimal(iter); + if (!std.mem.eql(u8, iter.next() orelse return error.UnexpectedEof, ")")) return error.ExpectedCloseParanthesis; + return point; +} + +fn readDecimal(iter: *TokenIterator(u8, .scalar)) !f32 { + const string = iter.next() orelse return error.UnexpectedEof; + return try parseFloat(string); +} + +fn readSymbol(iter: *TokenIterator(u8, .scalar)) ![]const u8 { + return iter.next() orelse return &.{}; +} + +// simpler float parsing function that runs quicker in debug +fn parseFloat(string: []const u8) !f32 { + var signed: bool = false; + var decimal_point: usize = string.len - 1; + var decimal: f64 = 0; + for (string, 0..) |c, i| { + switch (c) { + '-' => { + if (i == 0) signed = true else return error.UnexpectedCharacter; + }, + '0'...'9' => { + const digit: f64 = @floatFromInt(c - '0'); + decimal = 10 * decimal + digit; + }, + '.' => decimal_point = i, + else => return error.UnexpectedCharacter, + } + } + if (signed) decimal *= -1; + if (decimal_point < string.len - 1) { + const denom = std.math.pow(f64, 10, @floatFromInt(string.len - 1 - decimal_point)); + decimal /= denom; + } + return @floatCast(decimal); +} + +fn parseInt(string: []const u8) !i32 { + var signed: bool = false; + var decimal: i32 = 0; + for (string, 0..) |c, i| { + switch (c) { + '-' => { + if (i == 0) signed = true else return error.UnexpectedCharacter; + }, + '0'...'9' => { + const digit: i32 = @intCast(c - '0'); + decimal = 10 * decimal + digit; + }, + else => return error.UnexpectedCharacter, + } + } + return decimal; +} diff --git a/extras/bsp/src/bsp.zig b/extras/bsp/src/bsp.zig new file mode 100644 index 0000000..fe5f671 --- /dev/null +++ b/extras/bsp/src/bsp.zig @@ -0,0 +1,4 @@ +// top level exporter + +pub const QuakeMap = @import("QuakeMap.zig"); +pub const maploader = @import("maploader.zig"); diff --git a/extras/bsp/src/map.zig b/extras/bsp/src/map.zig new file mode 100644 index 0000000..e69de29 diff --git a/extras/bsp/src/maploader.zig b/extras/bsp/src/maploader.zig new file mode 100644 index 0000000..47f2682 --- /dev/null +++ b/extras/bsp/src/maploader.zig @@ -0,0 +1,310 @@ +pub const Settings = struct { + mapName: []const u8 = "map_", + vertexScale: f32 = 1.0 / 32.0, + rotation: core.Rotation = .{}, +}; + +pub const ColliderSpec = struct { + name: core.Name, +}; + +pub const TBMap = struct { + root: core.Entity, + meshes: std.ArrayListUnmanaged(core.Entity) = .{}, // each material has its own entity + colliders: std.ArrayListUnmanaged(core.Entity) = .{}, // each solid in worldspawn has it's own convex collider + colliderSpecs: std.ArrayListUnmanaged(ColliderSpec) = .{}, + allocator: std.mem.Allocator, + + pub fn create(allocator: std.mem.Allocator) !*@This() { + const self = try allocator.create(@This()); + + self.* = .{ + .allocator = allocator, + .root = try core.createEntity(), + }; + + _ = self.root.addComponent(core.Scene).?; + + return self; + } + + var fmtBuf: [256]u8 = undefined; + var fmtBuf2: [256]u8 = undefined; + pub fn addMeshScene(self: *@This(), builder: *MeshBuilder) !void { + const newEntity = try core.createEntity(); + const scene = newEntity.addComponent(core.Scene).?; + scene.setParent(self.root); + + const mesh = newEntity.addComponent(rend.MeshComponent).?; + mesh.setMesh(builder.meshName.utf8()); + + const textureName = try std.fmt.bufPrint(&fmtBuf, "t_map/{s}", .{builder.materialName.utf8()}); + mesh.setTexture(textureName); + + if (!rend.textureExists(textureName)) { + try assets.load( + assets.MakeImportRefOptions( + "Texture", + textureName, + // TODO don't hardcode the root path + .{ .path = try std.fmt.bufPrint(&fmtBuf2, "textures/{s}.png", .{builder.materialName.utf8()}) }, + ), + ); + } + // if the texture Does not exist issue an asset load request + + try self.meshes.append(self.allocator, newEntity); + } + + pub fn addPhysicsShape(self: *@This(), solid: QuakeMap.Solid, buildSettings: Settings) !void { + var floatList: std.ArrayListUnmanaged(f32) = .{}; + defer floatList.deinit(self.allocator); + var vertexCount: u32 = 0; + for (solid.faces.items) |face| { + for (face.vertices) |vert| { + // core.engine_log("adding vertex {any}", .{vert}); + const position = + core.Vectorf{ + .x = @floatCast(vert.data[0]), + .y = @floatCast(vert.data[1]), + .z = @floatCast(vert.data[2]), + }; + const final = buildSettings.rotation.rotateVector( + position.fmul(buildSettings.vertexScale), + ); + + try floatList.append(self.allocator, @floatCast(final.x)); + try floatList.append(self.allocator, @floatCast(final.y)); + try floatList.append(self.allocator, @floatCast(final.z)); + vertexCount += 1; + } + } + + const settings = try physics.ConvexHullShapeSettings.create( + @ptrCast(floatList.items.ptr), + vertexCount, + 12, + ); + defer settings.release(); + + // settings.setMaxConvexRadius(0.1); + var nameBuffer: [256]u8 = undefined; + + const shapeName = try std.fmt.bufPrint(&nameBuffer, "t_map/worldspawn_shape_{d}", .{self.colliderSpecs.items.len}); + + try physics.addShape(shapeName, .{ .convexHull = settings }); + + try self.colliderSpecs.append(self.allocator, .{ + .name = core.MakeName(shapeName), + }); + + { + const entity = try core.createEntity(); + const scene = entity.addComponent(core.Scene).?; + scene.setPosition(.{}); + // scene.setParent(self.root); + const collider = entity.addComponent(physics.PhysicsCollider).?; + try collider.setupByShapeName(core.MakeName(shapeName), .{ + .motion_type = .static, + .object_layer = physics.ObjectLayers.non_moving, + .friction = 0.8, + }); + try self.colliders.append(self.allocator, entity); + } + } + + pub fn destroy(self: *@This()) void { + for (self.meshes.items) |*m| { + m.destroy(); + } + + self.meshes.deinit(self.allocator); + + for (self.colliders.items) |*c| { + c.destroy(); + } + + self.colliders.deinit(self.allocator); + for (self.colliderSpecs.items) |spec| { + _ = spec; + // var name = spec.name; + // physics.gPhysicsRuntime.shapes.get(name.handle()).?.shape.release(); + } + self.colliderSpecs.deinit(self.allocator); + self.allocator.destroy(self); + self.root.destroy(); + } +}; + +// assumed to be consumed by submitMesh(). no deinit provided +pub const MeshBuilder = struct { + materialName: core.Name, + meshName: core.Name, + vertexOffset: u32 = 0, + + // these three use MeshAlloc + meshAlloc: std.mem.Allocator, + vertexList: std.ArrayListUnmanaged(rend.MeshVertex) = .{}, + indexList: std.ArrayListUnmanaged(u32) = .{}, + jointNames: std.ArrayListUnmanaged(JointNameEntry) = .{}, + // jointNames intentionally left empty, needed for the vk_meshpool interface. + // if i refactor it, this doesnt need to exist anymore, but that takes work... + + pub fn submitMesh(self: *@This()) !void { + const newMesh: MeshUpdate = .{ + .new = .{ + .vertices = try self.vertexList.toOwnedSlice(self.meshAlloc), + .indices = try self.indexList.toOwnedSlice(self.meshAlloc), + .name = self.meshName, + .jointNames = try self.jointNames.toOwnedSlice(self.meshAlloc), + .skeletonName = null, + }, + }; + + try rend.renderer.pushMeshUpdate(newMesh); + } + + pub fn addFace(self: *@This(), face: QuakeMap.Face, settings: Settings) !void { + const indexStart = self.vertexOffset; + + const count = face.vertices.len; + const uAxis: Vec3 = face.u_axis; + const vAxis: Vec3 = face.v_axis; + + const texSizeX: f32 = 64; + const texSizeY: f32 = 64; + + const d10 = face.vertices[1].sub(face.vertices[0]); + const d21 = face.vertices[2].sub(face.vertices[1]); + + const n = d10.cross(d21); + + var normal = + core.Vectorf{ + .x = @floatCast(n.data[0]), + .y = @floatCast(n.data[1]), + .z = @floatCast(n.data[2]), + }; + + normal = settings.rotation.rotateVector(normal); + if (normal.dot(.{ .y = 1.0 }) < 0.5) { + // return; + } + + // append all vertices to the vertex list + for (face.vertices) |vert| { + // uv_up axis + + const position = + core.Vectorf{ + .x = @floatCast(vert.data[0]), + .y = @floatCast(vert.data[1]), + .z = @floatCast(vert.data[2]), + }; + + const uAxisV = core.Vectorf.fromArray(uAxis.data); + const vAxisV = core.Vectorf.fromArray(vAxis.data); + + try self.vertexList.append(self.meshAlloc, .{ + .position = settings.rotation.rotateVector( + position.fmul(settings.vertexScale), + ), + // .normal: Vectorf = .{}, + .normal = normal, + .uv = .{ + .x = (uAxisV.dot(position) + face.shift_x) / texSizeX, + .y = (vAxisV.dot(position) + face.shift_y) / texSizeY, + }, + }); + + self.vertexOffset += 1; + } + + // generate ngons + try self.indexList.append(self.meshAlloc, indexStart); + try self.indexList.append(self.meshAlloc, indexStart + 1); + try self.indexList.append(self.meshAlloc, indexStart + 2); + + for (3..count) |j| { + const i: u32 = @intCast(j); + try self.indexList.append(self.meshAlloc, indexStart); + try self.indexList.append(self.meshAlloc, indexStart + i - 1); + try self.indexList.append(self.meshAlloc, indexStart + i); + } + } +}; + +pub fn LoadTrenchbroomMap(baseAllocator: std.mem.Allocator, settings: Settings) !*TBMap { + var err: QuakeMap.ErrorInfo = undefined; + const fileMapping = try core.fs().loadFile(settings.mapName); + defer core.fs().unmap(fileMapping); + + var arena = std.heap.ArenaAllocator.init(baseAllocator); + defer arena.deinit(); + const alloc = arena.allocator(); + + const map = try QuakeMap.read(arena.allocator(), fileMapping.bytesNoEnd(), &err); + + var builders: std.AutoHashMapUnmanaged(u32, MeshBuilder) = .{}; + + core.engine_log("worldspawn solids count: {d}", .{map.worldspawn.solids.items.len}); + + const meshAlloc = rend.getAllocator(); + + for (map.worldspawn.solids.items) |solid| { + for (solid.faces.items) |face| { + var name = core.MakeName(face.texture_name); + + if (!builders.contains(name.handle())) { + const meshName = try std.fmt.allocPrint(alloc, "map/m_{s}", .{face.texture_name}); + try builders.put(alloc, name.handle(), .{ + .materialName = name, + .meshName = core.MakeName(meshName), + .meshAlloc = meshAlloc, + }); + core.engine_log("new material found, {s}", .{face.texture_name}); + } + } + } + + // loop over all solids and list all materials. + // creating a unique mesh for each one + for (map.worldspawn.solids.items) |solid| { + for (solid.faces.items) |face| { + var name = core.MakeName(face.texture_name); + const builder = builders.getPtr(name.handle()).?; + try builder.addFace(face, settings); + } + } + + // loop over every vertex in quakeMap and push vertices and indices. + const tbMap = try TBMap.create(baseAllocator); + + var iterator = builders.valueIterator(); + while (iterator.next()) |builder| { + try tbMap.addMeshScene(builder); + try builder.submitMesh(); + } + + // + //for (map.worldspawn.solids.items) |solid| { + //try tbMap.addPhysicsShape(solid, settings); + // } + + // loop over all point entities look for info_player_start + return tbMap; +} + +const MeshUpdate = rend.MeshUpdate; +const JointNameEntry = rend.JointNameEntry; + +const za = QuakeMap.za; +const Vec3 = za.Vec3; +const Vec3d = za.Vec3_f64; +const QuakeMap = @import("QuakeMap.zig"); +const std = @import("std"); +const backlog = @import("Backlog"); +const rend = backlog.rend; +const physics = backlog.physics; +const core = backlog.core; +const assets = backlog.assets; diff --git a/extras/bsp/src/zalgebra/generic_vector.zig b/extras/bsp/src/zalgebra/generic_vector.zig new file mode 100644 index 0000000..f8f0e0e --- /dev/null +++ b/extras/bsp/src/zalgebra/generic_vector.zig @@ -0,0 +1,935 @@ +const std = @import("std"); +const root = @import("main.zig"); +const math = std.math; +const expectEqual = std.testing.expectEqual; +const expect = std.testing.expect; +const panic = std.debug.panic; + +pub const Vec2 = GenericVector(2, f32); +pub const Vec2_f64 = GenericVector(2, f64); +pub const Vec2_i32 = GenericVector(2, i32); +pub const Vec2_usize = GenericVector(2, usize); + +pub const Vec3 = GenericVector(3, f32); +pub const Vec3_f64 = GenericVector(3, f64); +pub const Vec3_i32 = GenericVector(3, i32); +pub const Vec3_usize = GenericVector(3, usize); + +pub const Vec4 = GenericVector(4, f32); +pub const Vec4_f64 = GenericVector(4, f64); +pub const Vec4_i32 = GenericVector(4, i32); +pub const Vec4_usize = GenericVector(4, usize); + +/// A generic vector. +pub fn GenericVector(comptime dimensions: comptime_int, comptime T: type) type { + if (@typeInfo(T) != .float and @typeInfo(T) != .int) { + @compileError("Vectors not implemented for " ++ @typeName(T)); + } + + if (dimensions < 2 or dimensions > 4) { + @compileError("Dimensions must be 2, 3 or 4!"); + } + + return extern struct { + const Self = @This(); + const Data = @Vector(dimensions, T); + + data: Data, + + pub const Component = switch (dimensions) { + 2 => enum { x, y }, + 3 => enum { x, y, z }, + 4 => enum { x, y, z, w }, + else => unreachable, + }; + + pub usingnamespace switch (dimensions) { + 2 => extern struct { + /// Construct new vector. + pub inline fn new(vx: T, vy: T) Self { + return .{ .data = [2]T{ vx, vy } }; + } + + /// Rotate vector by angle (in degrees) + pub fn rotate(self: Self, angle_in_degrees: T) Self { + const sin_theta = @sin(root.toRadians(angle_in_degrees)); + const cos_theta = @cos(root.toRadians(angle_in_degrees)); + return .{ .data = [2]T{ + cos_theta * self.x() - sin_theta * self.y(), + sin_theta * self.x() + cos_theta * self.y(), + } }; + } + + pub inline fn toVec3(self: Self, vz: T) GenericVector(3, T) { + return GenericVector(3, T).fromVec2(self, vz); + } + + pub inline fn toVec4(self: Self, vz: T, vw: T) GenericVector(4, T) { + return GenericVector(4, T).fromVec2(self, vz, vw); + } + + pub inline fn fromVec3(vec3: GenericVector(3, T)) Self { + return Self.new(vec3.x(), vec3.y()); + } + + pub inline fn fromVec4(vec4: GenericVector(4, T)) Self { + return Self.new(vec4.x(), vec4.y()); + } + }, + 3 => extern struct { + /// Construct new vector. + pub inline fn new(vx: T, vy: T, vz: T) Self { + return .{ .data = [3]T{ vx, vy, vz } }; + } + + pub inline fn z(self: Self) T { + return self.data[2]; + } + + pub inline fn zMut(self: *Self) *T { + return &self.data[2]; + } + + /// Shorthand for (0, 0, 1). + pub fn forward() Self { + return new(0, 0, 1); + } + + /// Shorthand for (0, 0, -1). + pub fn back() Self { + return forward().negate(); + } + + /// Construct the cross product (as vector) from two vectors. + pub fn cross(first_vector: Self, second_vector: Self) Self { + const x1 = first_vector.x(); + const y1 = first_vector.y(); + const z1 = first_vector.z(); + + const x2 = second_vector.x(); + const y2 = second_vector.y(); + const z2 = second_vector.z(); + + const result_x = (y1 * z2) - (z1 * y2); + const result_y = (z1 * x2) - (x1 * z2); + const result_z = (x1 * y2) - (y1 * x2); + return new(result_x, result_y, result_z); + } + + pub inline fn toVec2(self: Self) GenericVector(2, T) { + return GenericVector(2, T).fromVec3(self); + } + + pub inline fn toVec4(self: Self, vw: T) GenericVector(4, T) { + return GenericVector(4, T).fromVec3(self, vw); + } + + pub inline fn fromVec2(vec2: GenericVector(2, T), vz: T) Self { + return Self.new(vec2.x(), vec2.y(), vz); + } + + pub inline fn fromVec4(vec4: GenericVector(4, T)) Self { + return Self.new(vec4.x(), vec4.y(), vec4.z()); + } + }, + 4 => extern struct { + /// Construct new vector. + pub inline fn new(vx: T, vy: T, vz: T, vw: T) Self { + return .{ .data = [4]T{ vx, vy, vz, vw } }; + } + + /// Shorthand for (0, 0, 1, 0). + pub fn forward() Self { + return new(0, 0, 1, 0); + } + + /// Shorthand for (0, 0, -1, 0). + pub fn back() Self { + return forward().negate(); + } + + pub inline fn z(self: Self) T { + return self.data[2]; + } + + pub inline fn w(self: Self) T { + return self.data[3]; + } + + pub inline fn zMut(self: *Self) *T { + return &self.data[2]; + } + + pub inline fn wMut(self: *Self) *T { + return &self.data[3]; + } + + pub inline fn toVec2(self: Self) GenericVector(2, T) { + return GenericVector(2, T).fromVec4(self); + } + + pub inline fn toVec3(self: Self) GenericVector(3, T) { + return GenericVector(3, T).fromVec4(self); + } + + pub inline fn fromVec2(vec2: GenericVector(2, T), vz: T, vw: T) Self { + return Self.new(vec2.x(), vec2.y(), vz, vw); + } + + pub inline fn fromVec3(vec3: GenericVector(3, T), vw: T) Self { + return Self.new(vec3.x(), vec3.y(), vec3.z(), vw); + } + }, + else => unreachable, + }; + + pub inline fn x(self: Self) T { + return self.data[0]; + } + + pub inline fn y(self: Self) T { + return self.data[1]; + } + + pub inline fn xMut(self: *Self) *T { + return &self.data[0]; + } + + pub inline fn yMut(self: *Self) *T { + return &self.data[1]; + } + + /// Set all components to the same given value. + pub fn set(val: T) Self { + const result: Data = @splat(val); + return .{ .data = result }; + } + + /// Shorthand for (0..). + pub fn zero() Self { + return set(0); + } + + /// Shorthand for (1..). + pub fn one() Self { + return set(1); + } + + /// Shorthand for (0, 1). + pub fn up() Self { + return switch (dimensions) { + 2 => Self.new(0, 1), + 3 => Self.new(0, 1, 0), + 4 => Self.new(0, 1, 0, 0), + else => unreachable, + }; + } + + /// Shorthand for (0, -1). + pub fn down() Self { + return up().negate(); + } + + /// Shorthand for (1, 0). + pub fn right() Self { + return switch (dimensions) { + 2 => Self.new(1, 0), + 3 => Self.new(1, 0, 0), + 4 => Self.new(1, 0, 0, 0), + else => unreachable, + }; + } + + /// Shorthand for (-1, 0). + pub fn left() Self { + return right().negate(); + } + + /// Negate the given vector. + pub fn negate(self: Self) Self { + return self.scale(-1); + } + + /// Cast a type to another type. + /// It's like builtins: @intCast, @floatCast, @floatFromInt, @intFromFloat. + pub fn cast(self: Self, comptime dest_type: type) GenericVector(dimensions, dest_type) { + const dest_info = @typeInfo(dest_type); + + if (dest_info != .Float and dest_info != .Int) { + panic("Error, dest type should be integer or float.\n", .{}); + } + + var result: [dimensions]dest_type = undefined; + + for (result, 0..) |_, i| { + result[i] = math.lossyCast(dest_type, self.data[i]); + } + return .{ .data = result }; + } + + /// Construct new vector from slice. + pub fn fromSlice(slice: []const T) Self { + const result = slice[0..dimensions].*; + return .{ .data = result }; + } + + /// Transform vector to array. + pub fn toArray(self: Self) [dimensions]T { + return self.data; + } + + /// Return the angle (in degrees) between two vectors. + pub fn getAngle(first_vector: Self, second_vector: Self) T { + const dot_product = dot(norm(first_vector), norm(second_vector)); + return root.toDegrees(math.acos(dot_product)); + } + + /// Return the length (magnitude) of given vector. + /// √[x^2 + y^2 + z^2 ...] + pub fn length(self: Self) T { + return @sqrt(self.dot(self)); + } + + /// Return the distance between two points. + /// √[(x1 - x2)^2 + (y1 - y2)^2 + (z1 - z2)^2 ...] + pub fn distance(first_vector: Self, second_vector: Self) T { + return length(first_vector.sub(second_vector)); + } + + /// Construct new normalized vector from a given one. + pub fn norm(self: Self) Self { + const l = self.length(); + if (l == 0) { + return self; + } + const result = self.data / @as(Data, @splat(l)); + return .{ .data = result }; + } + + /// Return true if two vectors are equals. + pub fn eql(first_vector: Self, second_vector: Self) bool { + return @reduce(.And, first_vector.data == second_vector.data); + } + + /// Substraction between two given vector. + pub fn sub(first_vector: Self, second_vector: Self) Self { + const result = first_vector.data - second_vector.data; + return .{ .data = result }; + } + + /// Addition betwen two given vector. + pub fn add(first_vector: Self, second_vector: Self) Self { + const result = first_vector.data + second_vector.data; + return .{ .data = result }; + } + + /// Component wise multiplication betwen two given vector. + pub fn mul(first_vector: Self, second_vector: Self) Self { + const result = first_vector.data * second_vector.data; + return .{ .data = result }; + } + + /// Construct vector from the max components in two vectors + pub fn max(first_vector: Self, second_vector: Self) Self { + const result = @max(first_vector.data, second_vector.data); + return .{ .data = result }; + } + + /// Construct vector from the min components in two vectors + pub fn min(first_vector: Self, second_vector: Self) Self { + const result = @min(first_vector.data, second_vector.data); + return .{ .data = result }; + } + + /// Construct new vector after multiplying each components by a given scalar + pub fn scale(self: Self, scalar: T) Self { + const result = self.data * @as(Data, @splat(scalar)); + return .{ .data = result }; + } + + /// Return the dot product between two given vector. + /// (x1 * x2) + (y1 * y2) + (z1 * z2) ... + pub fn dot(first_vector: Self, second_vector: Self) T { + return @reduce(.Add, first_vector.data * second_vector.data); + } + + /// Linear interpolation between two vectors + pub fn lerp(first_vector: Self, second_vector: Self, t: T) Self { + const from = first_vector.data; + const to = second_vector.data; + + const result = from + (to - from) * @as(Data, @splat(t)); + return .{ .data = result }; + } + + pub inline fn swizzle2(self: Self, comptime vx: Component, comptime vy: Component) GenericVector(2, T) { + return GenericVector(2, T).new(self.data[@intFromEnum(vx)], self.data[@intFromEnum(vy)]); + } + + pub inline fn swizzle3(self: Self, comptime vx: Component, comptime vy: Component, comptime vz: Component) GenericVector(3, T) { + return GenericVector(3, T).new(self.data[@intFromEnum(vx)], self.data[@intFromEnum(vy)], self.data[@intFromEnum(vz)]); + } + + pub inline fn swizzle4(self: Self, comptime vx: Component, comptime vy: Component, comptime vz: Component, comptime vw: Component) GenericVector(4, T) { + return GenericVector(4, T).new(self.data[@intFromEnum(vx)], self.data[@intFromEnum(vy)], self.data[@intFromEnum(vz)], self.data[@intFromEnum(vw)]); + } + }; +} + +test "zalgebra.Vectors.eql" { + // Vec2 + { + const a = Vec2.new(1, 2); + const b = Vec2.new(1, 2); + const c = Vec2.new(1.5, 2); + + try expectEqual(Vec2.eql(a, b), true); + try expectEqual(Vec2.eql(a, c), false); + } + + // Vec3 + { + const a = Vec3.new(1, 2, 3); + const b = Vec3.new(1, 2, 3); + const c = Vec3.new(1.5, 2, 3); + + try expectEqual(Vec3.eql(a, b), true); + try expectEqual(Vec3.eql(a, c), false); + } + + // Vec4 + { + const a = Vec4.new(1, 2, 3, 4); + const b = Vec4.new(1, 2, 3, 4); + const c = Vec4.new(1.5, 2, 3, 4); + + try expectEqual(Vec4.eql(a, b), true); + try expectEqual(Vec4.eql(a, c), false); + } +} + +test "zalgebra.Vectors.set" { + // Vec2 + { + const a = Vec2.new(2.5, 2.5); + const b = Vec2.set(2.5); + try expectEqual(a, b); + } + + // Vec3 + { + const a = Vec3.new(2.5, 2.5, 2.5); + const b = Vec3.set(2.5); + try expectEqual(a, b); + } + + // Vec4 + { + const a = Vec4.new(2.5, 2.5, 2.5, 2.5); + const b = Vec4.set(2.5); + try expectEqual(a, b); + } +} + +test "zalgebra.Vectors.add" { + // Vec2 + { + const a = Vec2.one(); + const b = Vec2.one(); + try expectEqual(a.add(b), Vec2.set(2)); + } + + // Vec3 + { + const a = Vec3.one(); + const b = Vec3.one(); + try expectEqual(a.add(b), Vec3.set(2)); + } + + // Vec4 + { + const a = Vec4.one(); + const b = Vec4.one(); + try expectEqual(a.add(b), Vec4.set(2)); + } +} + +test "zalgebra.Vectors.negate" { + // Vec2 + { + const a = Vec2.set(5); + const a_negated = Vec2.set(-5); + try expectEqual(a.negate(), a_negated); + } + + // Vec3 + { + const a = Vec3.set(5); + const a_negated = Vec3.set(-5); + try expectEqual(a.negate(), a_negated); + } + + // Vec4 + { + const a = Vec4.set(5); + const a_negated = Vec4.set(-5); + try expectEqual(a.negate(), a_negated); + } +} + +test "zalgebra.Vectors.getAngle" { + // Vec2 + { + const a = Vec2.right(); + const b = Vec2.up(); + const c = Vec2.left(); + const d = Vec2.one(); + + try expectEqual(a.getAngle(a), 0); + try expectEqual(a.getAngle(b), 90); + try expectEqual(a.getAngle(c), 180); + try expectEqual(a.getAngle(d), 45); + } + + // Vec3 + { + const a = Vec3.right(); + const b = Vec3.up(); + const c = Vec3.left(); + const d = Vec3.new(1, 1, 0); + + try expectEqual(a.getAngle(a), 0); + try expectEqual(a.getAngle(b), 90); + try expectEqual(a.getAngle(c), 180); + try expectEqual(a.getAngle(d), 45); + } + + // Vec4 + { + const a = Vec4.right(); + const b = Vec4.up(); + const c = Vec4.left(); + const d = Vec4.new(1, 1, 0, 0); + + try expectEqual(a.getAngle(a), 0); + try expectEqual(a.getAngle(b), 90); + try expectEqual(a.getAngle(c), 180); + try expectEqual(a.getAngle(d), 45); + } +} + +test "zalgebra.Vectors.toArray" { + //Vec2 + { + const a = Vec2.up().toArray(); + const b = [_]f32{ 0, 1 }; + + try std.testing.expectEqualSlices(f32, &a, &b); + } + + //Vec3 + { + const a = Vec3.up().toArray(); + const b = [_]f32{ 0, 1, 0 }; + + try std.testing.expectEqualSlices(f32, &a, &b); + } + + //Vec4 + { + const a = Vec4.up().toArray(); + const b = [_]f32{ 0, 1, 0, 0 }; + + try std.testing.expectEqualSlices(f32, &a, &b); + } +} + +test "zalgebra.Vectors.length" { + // Vec2 + { + const a = Vec2.new(1.5, 2.6); + try expectEqual(a.length(), 3.00166606); + } + + // Vec3 + { + const a = Vec3.new(1.5, 2.6, 3.7); + try expectEqual(a.length(), 4.7644519); + } + + // Vec4 + { + const a = Vec4.new(1.5, 2.6, 3.7, 4.7); + try expectEqual(a.length(), 6.69253301); + } +} + +test "zalgebra.Vectors.distance" { + // Vec2 + { + const a = Vec2.zero(); + const b = Vec2.left(); + const c = Vec2.new(0, 5); + + try expectEqual(a.distance(b), 1); + try expectEqual(a.distance(c), 5); + } + + // Vec3 + { + const a = Vec3.zero(); + const b = Vec3.left(); + const c = Vec3.new(0, 5, 0); + + try expectEqual(a.distance(b), 1); + try expectEqual(a.distance(c), 5); + } + + // Vec4 + { + const a = Vec4.zero(); + const b = Vec4.left(); + const c = Vec4.new(0, 5, 0, 0); + + try expectEqual(a.distance(b), 1); + try expectEqual(a.distance(c), 5); + } +} + +test "zalgebra.Vectors.normalize" { + // Vec2 + { + const a = Vec2.new(1.5, 2.6); + const a_normalized = Vec2.new(0.499722480, 0.866185605); + try expectEqual(a.norm(), a_normalized); + } + + // Vec3 + { + const a = Vec3.new(1.5, 2.6, 3.7); + const a_normalized = Vec3.new(0.314831584, 0.545708060, 0.776584625); + try expectEqual(a.norm(), a_normalized); + } + + // Vec4 + { + const a = Vec4.new(1.5, 2.6, 3.7, 4.0); + const a_normalized = Vec4.new(0.241121411, 0.417943745, 0.594766139, 0.642990410); + try expectEqual(a.norm(), a_normalized); + } +} + +test "zalgebra.Vectors.scale" { + // Vec2 + { + const a = Vec2.new(1, 2); + const a_scaled = Vec2.new(5, 10); + try expectEqual(a.scale(5), a_scaled); + } + + // Vec3 + { + const a = Vec3.new(1, 2, 3); + const a_scaled = Vec3.new(5, 10, 15); + try expectEqual(a.scale(5), a_scaled); + } + + // Vec4 + { + const a = Vec4.new(1, 2, 3, 4); + const a_scaled = Vec4.new(5, 10, 15, 20); + try expectEqual(a.scale(5), a_scaled); + } +} + +test "zalgebra.Vectors.dot" { + // Vec2 + { + const a = Vec2.new(1.5, 2.6); + const b = Vec2.new(2.5, 3.45); + try expectEqual(a.dot(b), 12.7200002); + } + + // Vec3 + { + const a = Vec3.new(1.5, 2.6, 3.7); + const b = Vec3.new(2.5, 3.45, 1.0); + try expectEqual(a.dot(b), 16.42); + } + + // Vec4 + { + const a = Vec4.new(1.5, 2.6, 3.7, 5); + const b = Vec4.new(2.5, 3.45, 1.0, 1); + try expectEqual(a.dot(b), 21.4200000); + } +} + +test "zalgebra.Vectors.lerp" { + // Vec2 + { + const a = Vec2.new(-10, 0); + const b = Vec2.set(10); + try expectEqual(Vec2.lerp(a, b, 0.5), Vec2.new(0, 5)); + } + + // Vec3 + { + const a = Vec3.new(-10, 0, -10); + const b = Vec3.set(10); + try expectEqual(Vec3.lerp(a, b, 0.5), Vec3.new(0, 5, 0)); + } + + // Vec4 + { + const a = Vec4.new(-10, 0, -10, -10); + const b = Vec4.set(10); + try expectEqual(Vec4.lerp(a, b, 0.5), Vec4.new(0, 5, 0, 0)); + } +} + +test "zalgebra.Vectors.min" { + // Vec2 + { + const a = Vec2.new(10, -2); + const b = Vec2.new(-10, 5); + const minimum = Vec2.new(-10, -2); + try expectEqual(Vec2.min(a, b), minimum); + } + + // Vec3 + { + const a = Vec3.new(10, -2, 0); + const b = Vec3.new(-10, 5, 0); + const minimum = Vec3.new(-10, -2, 0); + try expectEqual(Vec3.min(a, b), minimum); + } + + // Vec4 + { + const a = Vec4.new(10, -2, 0, 1); + const b = Vec4.new(-10, 5, 0, 1.01); + const minimum = Vec4.new(-10, -2, 0, 1); + try expectEqual(Vec4.min(a, b), minimum); + } +} + +test "zalgebra.Vectors.max" { + // Vec2 + { + const a = Vec2.new(10, -2); + const b = Vec2.new(-10, 5); + const maximum = Vec2.new(10, 5); + try expectEqual(Vec2.max(a, b), maximum); + } + + // Vec3 + { + const a = Vec3.new(10, -2, 0); + const b = Vec3.new(-10, 5, 0); + const maximum = Vec3.new(10, 5, 0); + try expectEqual(Vec3.max(a, b), maximum); + } + + // Vec4 + { + const a = Vec4.new(10, -2, 0, 1); + const b = Vec4.new(-10, 5, 0, 1.01); + const maximum = Vec4.new(10, 5, 0, 1.01); + try expectEqual(Vec4.max(a, b), maximum); + } +} + +test "zalgebra.Vectors.fromSlice" { + // Vec2 + { + const slice = [_]f32{ 2, 4 }; + try expectEqual(Vec2.fromSlice(&slice), Vec2.new(2, 4)); + } + + // Vec3 + { + const slice = [_]f32{ 2, 4, 3 }; + try expectEqual(Vec3.fromSlice(&slice), Vec3.new(2, 4, 3)); + } + + // Vec4 + { + const slice = [_]f32{ 2, 4, 3, 6 }; + try expectEqual(Vec4.fromSlice(&slice), Vec4.new(2, 4, 3, 6)); + } +} + +test "zalgebra.Vectors.cast" { + // Vec2 + { + const a = Vec2_i32.new(3, 6); + const a_usize = Vec2_usize.new(3, 6); + try expectEqual(a.cast(usize), a_usize); + + const b = Vec2.new(3.5, 6.5); + const b_f64 = Vec2_f64.new(3.5, 6.5); + try expectEqual(b.cast(f64), b_f64); + + const c = Vec2_i32.new(3, 6); + const c_f32 = Vec2.new(3, 6); + try expectEqual(c.cast(f32), c_f32); + + const d = Vec2.new(3, 6); + const d_i32 = Vec2_i32.new(3, 6); + try expectEqual(d.cast(i32), d_i32); + } + + // Vec3 + { + const a = Vec3_i32.new(3, 6, 2); + const a_usize = Vec3_usize.new(3, 6, 2); + try expectEqual(a.cast(usize), a_usize); + + const b = Vec3.new(3.5, 6.5, 2); + const b_f64 = Vec3_f64.new(3.5, 6.5, 2); + try expectEqual(b.cast(f64), b_f64); + + const c = Vec3_i32.new(3, 6, 2); + const c_f32 = Vec3.new(3, 6, 2); + try expectEqual(c.cast(f32), c_f32); + + const d = Vec3.new(3, 6, 2); + const d_i32 = Vec3_i32.new(3, 6, 2); + try expectEqual(d.cast(i32), d_i32); + } + + // Vec4 + { + const a = Vec4_i32.new(3, 6, 2, 0); + const a_usize = Vec4_usize.new(3, 6, 2, 0); + try expectEqual(a.cast(usize), a_usize); + + const b = Vec4.new(3.5, 6.5, 2, 0); + const b_f64 = Vec4_f64.new(3.5, 6.5, 2, 0); + try expectEqual(b.cast(f64), b_f64); + + const c = Vec4_i32.new(3, 6, 2, 0); + const c_f32 = Vec4.new(3, 6, 2, 0); + try expectEqual(c.cast(f32), c_f32); + + const d = Vec4.new(3, 6, 2, 0); + const d_i32 = Vec4_i32.new(3, 6, 2, 0); + try expectEqual(d.cast(i32), d_i32); + } +} + +test "zalgebra.Vectors.cross" { + // Only for Vec3 + const a = Vec3.new(1.5, 2.6, 3.7); + const b = Vec3.new(2.5, 3.45, 1.0); + const c = Vec3.new(1.5, 2.6, 3.7); + + const result_1 = Vec3.cross(a, c); + const result_2 = Vec3.cross(a, b); + + try expectEqual(result_1, Vec3.zero()); + try expectEqual(result_2, Vec3.new(-10.1650009, 7.75, -1.32499980)); +} + +test "vector conversions 2 -> 3 -> 4" { + const v2 = Vec2.new(1, 2); + var v3 = Vec3.fromVec2(v2, 3); + var v4 = Vec4.fromVec3(v3, 4); + + try expectEqual(v3, Vec3.new(1, 2, 3)); + try expectEqual(v4, Vec4.new(1, 2, 3, 4)); + + v3 = v2.toVec3(3); + v4 = v2.toVec4(3, 4); + + try expectEqual(v3, Vec3.new(1, 2, 3)); + try expectEqual(v4, Vec4.new(1, 2, 3, 4)); +} + +test "vector conversions 4 -> 3 -> 2" { + const v4 = Vec4.new(1, 2, 3, 4); + var v3 = Vec3.fromVec4(v4); + var v2 = Vec2.fromVec3(v3); + + try expectEqual(v3, Vec3.new(1, 2, 3)); + try expectEqual(v2, Vec2.new(1, 2)); + + v3 = v4.toVec3(); + v2 = v4.toVec2(); + + try expectEqual(v3, Vec3.new(1, 2, 3)); + try expectEqual(v2, Vec2.new(1, 2)); +} + +test "vector conversions 2 -> 4" { + const v2 = Vec2.new(1, 2); + var v4 = Vec4.fromVec2(v2, 3, 4); + + try expectEqual(v4, Vec4.new(1, 2, 3, 4)); + + v4 = v2.toVec4(3, 4); + + try expectEqual(v4, Vec4.new(1, 2, 3, 4)); +} + +test "vector conversions 4 -> 2" { + const v4 = Vec4.new(1, 2, 3, 4); + var v2 = Vec2.fromVec4(v4); + + try expectEqual(v2, Vec2.new(1, 2)); + + v2 = v4.toVec2(); + + try expectEqual(v2, Vec2.new(1, 2)); +} + +// Just touching every component +// not testing every combination cause it's too many +test "swizzle2" { + const v2 = Vec2.new(1, 2); + const yx = v2.swizzle2(.y, .x); + try expectEqual(Vec2.new(2, 1), yx); + + const v3 = Vec3.new(1, 2, 3); + const zy = v3.swizzle2(.z, .y); + const xx = v3.swizzle2(.x, .x); + try expectEqual(Vec2.new(3, 2), zy); + try expectEqual(Vec2.new(1, 1), xx); + + const v4 = Vec4.new(1, 2, 3, 4); + const wz = v4.swizzle2(.w, .z); + const xy = v4.swizzle2(.x, .y); + try expectEqual(Vec2.new(4, 3), wz); + try expectEqual(Vec2.new(1, 2), xy); +} + +test "swizzle3" { + const v2 = Vec2.new(1, 2); + const yxy = v2.swizzle3(.y, .x, .y); + try expectEqual(Vec3.new(2, 1, 2), yxy); + + const v3 = Vec3.new(1, 2, 3); + const zyx = v3.swizzle3(.z, .y, .x); + try expectEqual(Vec3.new(3, 2, 1), zyx); + + const v4 = Vec4.new(1, 2, 3, 4); + const wzy = v4.swizzle3(.w, .z, .y); + const xxx = v4.swizzle3(.x, .x, .x); + try expectEqual(Vec3.new(4, 3, 2), wzy); + try expectEqual(Vec3.new(1, 1, 1), xxx); +} + +test "swizzle4" { + const v2 = Vec2.new(1, 2); + const yxyx = v2.swizzle4(.y, .x, .y, .x); + try expectEqual(Vec4.new(2, 1, 2, 1), yxyx); + + const v3 = Vec3.new(1, 2, 3); + const zyxz = v3.swizzle4(.z, .y, .x, .z); + try expectEqual(Vec4.new(3, 2, 1, 3), zyxz); + + const v4 = Vec4.new(1, 2, 3, 4); + const wzyx = v4.swizzle4(.w, .z, .y, .x); + try expectEqual(Vec4.new(4, 3, 2, 1), wzyx); +} diff --git a/extras/bsp/src/zalgebra/main.zig b/extras/bsp/src/zalgebra/main.zig new file mode 100644 index 0000000..a779336 --- /dev/null +++ b/extras/bsp/src/zalgebra/main.zig @@ -0,0 +1,72 @@ +//! Math utilities for graphics. +//! +const std = @import("std"); +const expectEqual = std.testing.expectEqual; +const math = std.math; + +pub usingnamespace @import("generic_vector.zig"); +pub usingnamespace @import("mat3.zig"); +pub usingnamespace @import("mat4.zig"); +pub usingnamespace @import("quaternion.zig"); + +/// Convert degrees to radians. +pub fn toRadians(degrees: anytype) @TypeOf(degrees) { + const T = @TypeOf(degrees); + + if (@typeInfo(T) != .Float) { + @compileError("Radians not implemented for " ++ @typeName(T)); + } + + return degrees * (math.pi / 180.0); +} + +/// Convert radians to degrees. +pub fn toDegrees(radians: anytype) @TypeOf(radians) { + const T = @TypeOf(radians); + + if (@typeInfo(T) != .Float) { + @compileError("Radians not implemented for " ++ @typeName(T)); + } + + return radians * (180.0 / math.pi); +} + +/// Linear interpolation between two floats. +/// `t` is used to interpolate between `from` and `to`. +pub fn lerp(comptime T: type, from: T, to: T, t: T) T { + if (@typeInfo(T) != .Float) { + @compileError("Lerp not implemented for " ++ @typeName(T)); + } + + return (1 - t) * from + t * to; +} + +test "zalgebra.toRadians" { + try expectEqual(toRadians(@as(f32, 0)), 0); + try expectEqual(toRadians(@as(f32, 30)), 0.523598790); + try expectEqual(toRadians(@as(f32, 45)), 0.78539818); + try expectEqual(toRadians(@as(f32, 60)), 1.04719758); + try expectEqual(toRadians(@as(f32, 90)), 1.57079637); //math.pi / 2 + try expectEqual(toRadians(@as(f32, 180)), 3.14159274); //math.pi + try expectEqual(toRadians(@as(f32, 270)), 4.71238899); + try expectEqual(toRadians(@as(f32, 360)), 6.28318548); //math.pi * 2 +} + +test "zalgebra.toDegrees" { + try expectEqual(toDegrees(@as(f32, 0)), 0); + try expectEqual(toDegrees(@as(f32, 0.5)), 28.6478900); + try expectEqual(toDegrees(@as(f32, 1)), 57.2957801); + try expectEqual(toDegrees(@as(f32, 1.57079637)), 90); //math.pi / 2 + try expectEqual(toDegrees(@as(f32, 3.14159274)), 180); //math.pi + try expectEqual(toDegrees(@as(f32, 4.71238899)), 270); + try expectEqual(toDegrees(@as(f32, 6.28318548)), 360); //math.pi * 2 +} + +test "zalgebra.lerp" { + const from: f32 = 0; + const to: f32 = 10; + + try expectEqual(lerp(f32, from, to, 0), 0); + try expectEqual(lerp(f32, from, to, 0.5), 5); + try expectEqual(lerp(f32, from, to, 1), 10); +} diff --git a/extras/bsp/src/zalgebra/mat3.zig b/extras/bsp/src/zalgebra/mat3.zig new file mode 100644 index 0000000..224eb75 --- /dev/null +++ b/extras/bsp/src/zalgebra/mat3.zig @@ -0,0 +1,452 @@ +const std = @import("std"); +const math = std.math; +const meta = std.meta; +const mem = std.mem; +const expectEqual = std.testing.expectEqual; +const root = @import("main.zig"); +const generic_vector = @import("generic_vector.zig"); +const quat = @import("quaternion.zig"); + +const Vec3 = generic_vector.Vec3; +const Vec3_f64 = generic_vector.Vec3_f64; +const GenericVector = generic_vector.GenericVector; +const Quaternion = quat.Quaternion; +const Quat = quat.Quat; + +pub const Mat3 = Mat3x3(f32); +pub const Mat3_f64 = Mat3x3(f64); + +/// A column-major 3x3 matrix +/// Note: Column-major means accessing data like m.data[COLUMN][ROW]. +pub fn Mat3x3(comptime T: type) type { + if (@typeInfo(T) != .Float) { + @compileError("Mat3x3 not implemented for " ++ @typeName(T)); + } + + const Vector3 = GenericVector(3, T); + + return extern struct { + data: [3][3]T, + + const Self = @This(); + + /// Shorthand for identity matrix. + pub fn identity() Self { + return .{ + .data = .{ + .{ 1, 0, 0 }, + .{ 0, 1, 0 }, + .{ 0, 0, 1 }, + }, + }; + } + + /// Shorthand for matrix with all zeros. + pub fn zero() Self { + return Self.set(0); + } + + /// Set all mat3 values to given value. + pub fn set(value: T) Self { + const data: [9]T = .{value} ** 9; + return Self.fromSlice(&data); + } + + /// Construct new 3x3 matrix from given slice. + pub fn fromSlice(data: *const [9]T) Self { + return .{ + .data = .{ + data[0..3].*, + data[3..6].*, + data[6..9].*, + }, + }; + } + + /// Negate the given matrix. + pub fn negate(self: Self) Self { + var result = self; + for (0..result.data.len) |column| { + for (0..result.data[column].len) |row| { + result.data[column][row] = -result.data[column][row]; + } + } + return result; + } + + /// Transpose the given matrix. + pub fn transpose(self: Self) Self { + var result = self; + for (0..result.data.len) |column| { + for (column..result.data[column].len) |row| { + std.mem.swap(T, &result.data[column][row], &result.data[row][column]); + } + } + return result; + } + + /// Return a pointer to the inner data of the matrix. + pub fn getData(self: *const Self) *const T { + return @ptrCast(&self.data); + } + + /// Return true if two matrices are equals. + pub fn eql(left: Self, right: Self) bool { + return meta.eql(left, right); + } + + pub fn mulByVec3(self: Self, v: Vector3) Vector3 { + const x = (self.data[0][0] * v.x()) + (self.data[1][0] * v.y()) + (self.data[2][0] * v.z()); + const y = (self.data[0][1] * v.x()) + (self.data[1][1] * v.y()) + (self.data[2][1] * v.z()); + const z = (self.data[0][2] * v.x()) + (self.data[1][2] * v.y()) + (self.data[2][2] * v.z()); + + return Vector3.new(x, y, z); + } + + /// Construct a 3x3 matrix from given axis and angle (in degrees). + pub fn fromRotation(angle_in_degrees: T, axis: Vector3) Self { + var result = Self.identity(); + + const norm_axis = axis.norm(); + + const sin_theta = @sin(root.toRadians(angle_in_degrees)); + const cos_theta = @cos(root.toRadians(angle_in_degrees)); + const cos_value = 1 - cos_theta; + + const x = norm_axis.x(); + const y = norm_axis.y(); + const z = norm_axis.z(); + + result.data[0][0] = (x * x * cos_value) + cos_theta; + result.data[0][1] = (x * y * cos_value) + (z * sin_theta); + result.data[0][2] = (x * z * cos_value) - (y * sin_theta); + + result.data[1][0] = (y * x * cos_value) - (z * sin_theta); + result.data[1][1] = (y * y * cos_value) + cos_theta; + result.data[1][2] = (y * z * cos_value) + (x * sin_theta); + + result.data[2][0] = (z * x * cos_value) + (y * sin_theta); + result.data[2][1] = (z * y * cos_value) - (x * sin_theta); + result.data[2][2] = (z * z * cos_value) + cos_theta; + + return result; + } + + pub fn rotate(self: Self, angle_in_degrees: T, axis: Vector3) Self { + const rotation_mat = Self.fromRotation(angle_in_degrees, axis); + return Self.mul(self, rotation_mat); + } + + /// Construct a rotation matrix from euler angles (X * Y * Z). + /// Order matters because matrix multiplication are NOT commutative. + pub fn fromEulerAngles(euler_angle: Vector3) Self { + const x = Self.fromRotation(euler_angle.x(), Vector3.right()); + const y = Self.fromRotation(euler_angle.y(), Vector3.up()); + const z = Self.fromRotation(euler_angle.z(), Vector3.forward()); + + return z.mul(y.mul(x)); + } + + /// Ortho normalize given matrix. + pub fn orthoNormalize(self: Self) Self { + const column_1 = Vector3.new(self.data[0][0], self.data[0][1], self.data[0][2]).norm(); + const column_2 = Vector3.new(self.data[1][0], self.data[1][1], self.data[1][2]).norm(); + const column_3 = Vector3.new(self.data[2][0], self.data[2][1], self.data[2][2]).norm(); + + var result = self; + + result.data[0][0] = column_1.x(); + result.data[0][1] = column_1.y(); + result.data[0][2] = column_1.z(); + + result.data[1][0] = column_2.x(); + result.data[1][1] = column_2.y(); + result.data[1][2] = column_2.z(); + + result.data[2][0] = column_3.x(); + result.data[2][1] = column_3.y(); + result.data[2][2] = column_3.z(); + + return result; + } + + /// Return the rotation as Euler angles in degrees. + /// Taken from Mike Day at Insomniac Games (and `glm` as the same function). + /// For more details: https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2012/07/euler-angles1.pdf + pub fn extractEulerAngles(self: Self) Vector3 { + const m = self.orthoNormalize(); + + const theta_x = math.atan2(m.data[1][2], m.data[2][2]); + const c2 = @sqrt(math.pow(T, m.data[0][0], 2) + math.pow(T, m.data[0][1], 2)); + const theta_y = math.atan2(-m.data[0][2], @sqrt(c2)); + const s1 = @sin(theta_x); + const c1 = @cos(theta_x); + const theta_z = math.atan2(s1 * m.data[2][0] - c1 * m.data[1][0], c1 * m.data[1][1] - s1 * m.data[2][1]); + + return Vector3.new(root.toDegrees(theta_x), root.toDegrees(theta_y), root.toDegrees(theta_z)); + } + + pub fn fromScale(axis: Vector3) Self { + var result = Self.identity(); + + result.data[0][0] = axis.x(); + result.data[1][1] = axis.y(); + result.data[2][2] = axis.z(); + + return result; + } + + pub fn scale(self: Self, axis: Vector3) Self { + const scale_mat = Self.fromScale(axis); + return Self.mul(scale_mat, self); + } + + pub fn extractScale(self: Self) Vector3 { + const scale_x = Vector3.new(self.data[0][0], self.data[0][1], self.data[0][2]); + const scale_y = Vector3.new(self.data[1][0], self.data[1][1], self.data[1][2]); + const scale_z = Vector3.new(self.data[2][0], self.data[2][1], self.data[2][2]); + + return Vector3.new(scale_x.length(), scale_y.length(), scale_z.length()); + } + + /// Matrices' multiplication. + /// Produce a new matrix from given two matrices. + pub fn mul(left: Self, right: Self) Self { + var result = Self.identity(); + for (0..result.data.len) |column| { + for (0..result.data[column].len) |row| { + var sum: T = 0; + + for (0..left.data.len) |left_column| { + sum += left.data[left_column][row] * right.data[column][left_column]; + } + + result.data[column][row] = sum; + } + } + return result; + } + + /// Calculate determinant of the given 3x3 matrix. + pub fn det(self: Self) T { + var s: [3]T = undefined; + s[0] = self.data[0][0] * (self.data[1][1] * self.data[2][2] - self.data[1][2] * self.data[2][1]); + s[1] = self.data[0][1] * (self.data[1][0] * self.data[2][2] - self.data[1][2] * self.data[2][0]); + s[2] = self.data[0][2] * (self.data[1][0] * self.data[2][1] - self.data[1][1] * self.data[2][0]); + return s[0] - s[1] + s[2]; + } + + /// Construct inverse 3x3 from given matrix. + /// Note: This is not the most efficient way to do this. + /// TODO: Make it more efficient. + pub fn inv(self: Self) Self { + var inv_mat: Self = undefined; + + const determ = 1 / det(self); + + inv_mat.data[0][0] = determ * (self.data[1][1] * self.data[2][2] - self.data[1][2] * self.data[2][1]); + inv_mat.data[0][1] = determ * -(self.data[0][1] * self.data[2][2] - self.data[0][2] * self.data[2][1]); + inv_mat.data[0][2] = determ * (self.data[0][1] * self.data[1][2] - self.data[0][2] * self.data[1][1]); + + inv_mat.data[1][0] = determ * -(self.data[1][0] * self.data[2][2] - self.data[1][2] * self.data[2][0]); + inv_mat.data[1][1] = determ * (self.data[0][0] * self.data[2][2] - self.data[0][2] * self.data[2][0]); + inv_mat.data[1][2] = determ * -(self.data[0][0] * self.data[1][2] - self.data[0][2] * self.data[1][0]); + + inv_mat.data[2][0] = determ * (self.data[1][0] * self.data[2][1] - self.data[1][1] * self.data[2][0]); + inv_mat.data[2][1] = determ * -(self.data[0][0] * self.data[2][1] - self.data[0][1] * self.data[2][0]); + inv_mat.data[2][2] = determ * (self.data[0][0] * self.data[1][1] - self.data[0][1] * self.data[1][0]); + + return inv_mat; + } + + /// Print the 3x3 to stderr. + pub fn debugPrint(self: Self) void { + const print = std.debug.print; + + print("({d}, {d}, {d})\n", .{ + self.data[0][0], + self.data[1][0], + self.data[2][0], + }); + + print("({d}, {d}, {d})\n", .{ + self.data[0][1], + self.data[1][1], + self.data[2][1], + }); + + print("({d}, {d}, {d})\n", .{ + self.data[0][2], + self.data[1][2], + self.data[2][2], + }); + } + + /// Cast a type to another type. + /// It's like builtins: @intCast, @floatCast, @floatFromInt, @intFromFloat. + pub fn cast(self: Self, comptime dest_type: type) Mat3x3(dest_type) { + const dest_info = @typeInfo(dest_type); + + if (dest_info != .Float) { + std.debug.panic("Error, dest type should be float.\n", .{}); + } + + var result: Mat3x3(dest_type) = undefined; + for (0..result.data.len) |column| { + for (0..result.data[column].len) |row| { + result.data[column][row] = @floatCast(self.data[column][row]); + } + } + return result; + } + }; +} + +test "zalgebra.Mat3.eql" { + const a = Mat3.identity(); + const b = Mat3.identity(); + const c = Mat3.zero(); + + try expectEqual(Mat3.eql(a, b), true); + try expectEqual(Mat3.eql(a, c), false); +} + +test "zalgebra.Mat3.set" { + const a = Mat3.set(12); + const b = Mat3{ + .data = .{ + .{ 12, 12, 12 }, + .{ 12, 12, 12 }, + .{ 12, 12, 12 }, + }, + }; + + try expectEqual(a, b); +} + +test "zalgebra.Mat3.negate" { + const a = Mat3{ + .data = .{ + .{ 1, 2, 3 }, + .{ 5, -6, 7 }, + .{ 9, 10, 11 }, + }, + }; + const a_negated = Mat3{ + .data = .{ + .{ -1, -2, -3 }, + .{ -5, 6, -7 }, + .{ -9, -10, -11 }, + }, + }; + + try expectEqual(a.negate(), a_negated); +} + +test "zalgebra.Mat3.transpose" { + const a = Mat3{ + .data = .{ + .{ 1, 2, 3 }, + .{ 5, 6, 7 }, + .{ 9, 10, 11 }, + }, + }; + const b = Mat3{ + .data = .{ + .{ 1, 5, 9 }, + .{ 2, 6, 10 }, + .{ 3, 7, 11 }, + }, + }; + + try expectEqual(a.transpose(), b); +} + +test "zalgebra.Mat3.fromSlice" { + const data = [_]f32{ 1, 0, 0, 0, 1, 0, 0, 0, 1 }; + const result = Mat3.fromSlice(&data); + + try expectEqual(result, Mat3.identity()); +} + +test "zalgebra.Mat3.fromScale" { + const a = Mat3.fromScale(Vec3.new(2, 3, 4)); + + try expectEqual(a, Mat3{ + .data = .{ + .{ 2, 0, 0 }, + .{ 0, 3, 0 }, + .{ 0, 0, 4 }, + }, + }); +} + +test "zalgebra.Mat3.scale" { + const a = Mat3.fromScale(Vec3.new(2, 3, 4)); + const result = Mat3.scale(a, Vec3.set(2)); + + try expectEqual(result, Mat3{ + .data = .{ + .{ 4, 0, 0 }, + .{ 0, 6, 0 }, + .{ 0, 0, 8 }, + }, + }); +} + +test "zalgebra.Mat3.det" { + const a: Mat3 = .{ + .data = .{ + .{ 2, 0, 4 }, + .{ 0, 2, 0 }, + .{ 4, 0, 2 }, + }, + }; + + try expectEqual(a.det(), -24); +} + +test "zalgebra.Mat3.inv" { + const a: Mat3 = .{ + .data = .{ + .{ 2, 0, 4 }, + .{ 0, 2, 0 }, + .{ 4, 0, 2 }, + }, + }; + + try expectEqual(a.inv(), Mat3{ + .data = .{ + .{ -0.1666666716337204, 0, 0.3333333432674408 }, + .{ 0, 0.5, 0 }, + .{ 0.3333333432674408, 0, -0.1666666716337204 }, + }, + }); +} + +test "zalgebra.Mat3.extractEulerAngles" { + const a = Mat3.fromEulerAngles(Vec3.new(45, -5, 20)); + try expectEqual(a.extractEulerAngles(), Vec3.new(45.000003814697266, -4.99052524, 19.999998092651367)); +} + +test "zalgebra.Mat3.extractScale" { + var a = Mat3.fromScale(Vec3.new(2, 4, 8)); + a = a.scale(Vec3.new(2, 4, 8)); + + try expectEqual(a.extractScale(), Vec3.new(4, 16, 64)); +} + +test "zalgebra.Mat3.cast" { + const a = Mat3{ .data = .{ + .{ 0.9961947202682495, 0, -0.08715573698282242 }, + .{ 0.06162841245532036, 0.7071067690849304, 0.704416036605835 }, + .{ 0.06162841245532036, -0.7071067690849304, 0.704416036605835 }, + } }; + const a_f64 = Mat3_f64{ .data = .{ + .{ 0.9961947202682495, 0, -0.08715573698282242 }, + .{ 0.06162841245532036, 0.7071067690849304, 0.704416036605835 }, + .{ 0.06162841245532036, -0.7071067690849304, 0.704416036605835 }, + } }; + try expectEqual(a.cast(f64), a_f64); + try expectEqual(a_f64.cast(f32), a); +} diff --git a/extras/bsp/src/zalgebra/mat4.zig b/extras/bsp/src/zalgebra/mat4.zig new file mode 100644 index 0000000..2dad4bd --- /dev/null +++ b/extras/bsp/src/zalgebra/mat4.zig @@ -0,0 +1,718 @@ +const std = @import("std"); +const math = std.math; +const meta = std.meta; +const mem = std.mem; +const expectEqual = std.testing.expectEqual; +const root = @import("main.zig"); +const generic_vector = @import("generic_vector.zig"); +const quat = @import("quaternion.zig"); + +const Vec3 = generic_vector.Vec3; +const Vec3_f64 = generic_vector.Vec3_f64; +const GenericVector = generic_vector.GenericVector; +const Quaternion = quat.Quaternion; +const Quat = quat.Quat; + +pub const Mat4 = Mat4x4(f32); +pub const Mat4_f64 = Mat4x4(f64); +pub const perspective = Mat4.perspective; +pub const perspectiveReversedZ = Mat4.perspectiveReversedZ; +pub const orthographic = Mat4.orthographic; +pub const lookAt = Mat4.lookAt; + +/// A column-major 4x4 matrix +/// Note: Column-major means accessing data like m.data[COLUMN][ROW]. +pub fn Mat4x4(comptime T: type) type { + if (@typeInfo(T) != .Float) { + @compileError("Mat4x4 not implemented for " ++ @typeName(T)); + } + + const Vector3 = GenericVector(3, T); + const Vector4 = GenericVector(4, T); + + return extern struct { + data: [4][4]T, + + const Self = @This(); + + /// Shorthand for identity matrix. + pub fn identity() Self { + return .{ + .data = .{ + .{ 1, 0, 0, 0 }, + .{ 0, 1, 0, 0 }, + .{ 0, 0, 1, 0 }, + .{ 0, 0, 0, 1 }, + }, + }; + } + + /// Shorthand for matrix with all zeros. + pub fn zero() Self { + return Self.set(0); + } + + /// Set all mat4 values to given value. + pub fn set(value: T) Self { + const data: [16]T = .{value} ** 16; + return Self.fromSlice(&data); + } + + /// Construct new 4x4 matrix from given slice. + pub fn fromSlice(data: *const [16]T) Self { + return .{ + .data = .{ + data[0..4].*, + data[4..8].*, + data[8..12].*, + data[12..16].*, + }, + }; + } + + /// Negate the given matrix. + pub fn negate(self: Self) Self { + var result = self; + for (0..result.data.len) |column| { + for (0..result.data[column].len) |row| { + result.data[column][row] = -result.data[column][row]; + } + } + return result; + } + + /// Transpose the given matrix. + pub fn transpose(self: Self) Self { + var result = self; + for (0..result.data.len) |column| { + for (column..4) |row| { + std.mem.swap(T, &result.data[column][row], &result.data[row][column]); + } + } + return result; + } + + /// Return a pointer to the inner data of the matrix. + pub fn getData(self: *const Self) *const T { + return @ptrCast(&self.data); + } + + /// Return true if two matrices are equals. + pub fn eql(left: Self, right: Self) bool { + return meta.eql(left, right); + } + + pub fn mulByVec4(self: Self, v: Vector4) Vector4 { + const x = (self.data[0][0] * v.x()) + (self.data[1][0] * v.y()) + (self.data[2][0] * v.z()) + (self.data[3][0] * v.w()); + const y = (self.data[0][1] * v.x()) + (self.data[1][1] * v.y()) + (self.data[2][1] * v.z()) + (self.data[3][1] * v.w()); + const z = (self.data[0][2] * v.x()) + (self.data[1][2] * v.y()) + (self.data[2][2] * v.z()) + (self.data[3][2] * v.w()); + const w = (self.data[0][3] * v.x()) + (self.data[1][3] * v.y()) + (self.data[2][3] * v.z()) + (self.data[3][3] * v.w()); + + return Vector4.new(x, y, z, w); + } + + /// Construct 4x4 translation matrix by multiplying identity matrix and + /// given translation vector. + pub fn fromTranslate(axis: Vector3) Self { + var result = Self.identity(); + result.data[3][0] = axis.data[0]; + result.data[3][1] = axis.data[1]; + result.data[3][2] = axis.data[2]; + + return result; + } + + /// Make a translation between the given matrix and the given axis. + pub fn translate(self: Self, axis: Vector3) Self { + const trans_mat = Self.fromTranslate(axis); + return Self.mul(trans_mat, self); + } + + /// Get translation Vec3 from current matrix. + pub fn extractTranslation(self: Self) Vector3 { + return Vector3.new(self.data[3][0], self.data[3][1], self.data[3][2]); + } + + /// Construct a 4x4 matrix from given axis and angle (in degrees). + pub fn fromRotation(angle_in_degrees: T, axis: Vector3) Self { + var result = Self.identity(); + + const norm_axis = axis.norm(); + + const sin_theta = @sin(root.toRadians(angle_in_degrees)); + const cos_theta = @cos(root.toRadians(angle_in_degrees)); + const cos_value = 1 - cos_theta; + + const x = norm_axis.x(); + const y = norm_axis.y(); + const z = norm_axis.z(); + + result.data[0][0] = (x * x * cos_value) + cos_theta; + result.data[0][1] = (x * y * cos_value) + (z * sin_theta); + result.data[0][2] = (x * z * cos_value) - (y * sin_theta); + + result.data[1][0] = (y * x * cos_value) - (z * sin_theta); + result.data[1][1] = (y * y * cos_value) + cos_theta; + result.data[1][2] = (y * z * cos_value) + (x * sin_theta); + + result.data[2][0] = (z * x * cos_value) + (y * sin_theta); + result.data[2][1] = (z * y * cos_value) - (x * sin_theta); + result.data[2][2] = (z * z * cos_value) + cos_theta; + + return result; + } + + pub fn rotate(self: Self, angle_in_degrees: T, axis: Vector3) Self { + const rotation_mat = Self.fromRotation(angle_in_degrees, axis); + return Self.mul(self, rotation_mat); + } + + /// Construct a rotation matrix from euler angles (X * Y * Z). + /// Order matters because matrix multiplication are NOT commutative. + pub fn fromEulerAngles(euler_angle: Vector3) Self { + const x = Self.fromRotation(euler_angle.x(), Vector3.right()); + const y = Self.fromRotation(euler_angle.y(), Vector3.up()); + const z = Self.fromRotation(euler_angle.z(), Vector3.forward()); + + return z.mul(y.mul(x)); + } + + /// Ortho normalize given matrix. + pub fn orthoNormalize(self: Self) Self { + const column_1 = Vector3.new(self.data[0][0], self.data[0][1], self.data[0][2]).norm(); + const column_2 = Vector3.new(self.data[1][0], self.data[1][1], self.data[1][2]).norm(); + const column_3 = Vector3.new(self.data[2][0], self.data[2][1], self.data[2][2]).norm(); + + var result = self; + + result.data[0][0] = column_1.x(); + result.data[0][1] = column_1.y(); + result.data[0][2] = column_1.z(); + + result.data[1][0] = column_2.x(); + result.data[1][1] = column_2.y(); + result.data[1][2] = column_2.z(); + + result.data[2][0] = column_3.x(); + result.data[2][1] = column_3.y(); + result.data[2][2] = column_3.z(); + + return result; + } + + /// Return the rotation as Euler angles in degrees. + /// Taken from Mike Day at Insomniac Games (and `glm` as the same function). + /// For more details: https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2012/07/euler-angles1.pdf + pub fn extractEulerAngles(self: Self) Vector3 { + const m = self.orthoNormalize(); + + const theta_x = math.atan2(m.data[1][2], m.data[2][2]); + const c2 = @sqrt(math.pow(T, m.data[0][0], 2) + math.pow(T, m.data[0][1], 2)); + const theta_y = math.atan2(-m.data[0][2], @sqrt(c2)); + const s1 = @sin(theta_x); + const c1 = @cos(theta_x); + const theta_z = math.atan2(s1 * m.data[2][0] - c1 * m.data[1][0], c1 * m.data[1][1] - s1 * m.data[2][1]); + + return Vector3.new(root.toDegrees(theta_x), root.toDegrees(theta_y), root.toDegrees(theta_z)); + } + + pub fn fromScale(axis: Vector3) Self { + var result = Self.identity(); + + result.data[0][0] = axis.x(); + result.data[1][1] = axis.y(); + result.data[2][2] = axis.z(); + + return result; + } + + pub fn scale(self: Self, axis: Vector3) Self { + const scale_mat = Self.fromScale(axis); + return Self.mul(scale_mat, self); + } + + pub fn extractScale(self: Self) Vector3 { + const scale_x = Vector3.new(self.data[0][0], self.data[0][1], self.data[0][2]); + const scale_y = Vector3.new(self.data[1][0], self.data[1][1], self.data[1][2]); + const scale_z = Vector3.new(self.data[2][0], self.data[2][1], self.data[2][2]); + + return Vector3.new(scale_x.length(), scale_y.length(), scale_z.length()); + } + + /// Construct a perspective 4x4 matrix. + /// Note: Field of view is given in degrees. + /// Also for more details https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml. + pub fn perspective(fovy_in_degrees: T, aspect_ratio: T, z_near: T, z_far: T) Self { + var result = Self.identity(); + + const f = 1 / @tan(root.toRadians(fovy_in_degrees) * 0.5); + + result.data[0][0] = f / aspect_ratio; + result.data[1][1] = f; + result.data[2][2] = (z_near + z_far) / (z_near - z_far); + result.data[2][3] = -1; + result.data[3][2] = 2 * z_far * z_near / (z_near - z_far); + result.data[3][3] = 0; + + return result; + } + + /// Construct a perspective 4x4 matrix with reverse Z and infinite far plane. + /// Note: Field of view is given in degrees. + /// Also for more details https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml. + /// For Reversed-Z details https://nlguillemot.wordpress.com/2016/12/07/reversed-z-in-opengl/ + pub fn perspectiveReversedZ(fovy_in_degrees: T, aspect_ratio: T, z_near: T) Self { + var result = Self.identity(); + + const f = 1 / @tan(root.toRadians(fovy_in_degrees) * 0.5); + + result.data[0][0] = f / aspect_ratio; + result.data[1][1] = f; + result.data[2][2] = 0; + result.data[2][3] = -1; + result.data[3][2] = z_near; + result.data[3][3] = 0; + + return result; + } + + /// Construct an orthographic 4x4 matrix. + pub fn orthographic(left: T, right: T, bottom: T, top: T, z_near: T, z_far: T) Self { + var result = Self.zero(); + + result.data[0][0] = 2 / (right - left); + result.data[1][1] = 2 / (top - bottom); + result.data[2][2] = 2 / (z_near - z_far); + result.data[3][3] = 1; + + result.data[3][0] = (left + right) / (left - right); + result.data[3][1] = (bottom + top) / (bottom - top); + result.data[3][2] = (z_far + z_near) / (z_near - z_far); + + return result; + } + + /// Right-handed lookAt function. + pub fn lookAt(eye: Vector3, target: Vector3, up: Vector3) Self { + const f = Vector3.sub(target, eye).norm(); + const s = Vector3.cross(f, up).norm(); + const u = Vector3.cross(s, f); + + var result: Self = undefined; + result.data[0][0] = s.x(); + result.data[0][1] = u.x(); + result.data[0][2] = -f.x(); + result.data[0][3] = 0; + + result.data[1][0] = s.y(); + result.data[1][1] = u.y(); + result.data[1][2] = -f.y(); + result.data[1][3] = 0; + + result.data[2][0] = s.z(); + result.data[2][1] = u.z(); + result.data[2][2] = -f.z(); + result.data[2][3] = 0; + + result.data[3][0] = -Vector3.dot(s, eye); + result.data[3][1] = -Vector3.dot(u, eye); + result.data[3][2] = Vector3.dot(f, eye); + result.data[3][3] = 1; + + return result; + } + + /// Matrices' multiplication. + /// Produce a new matrix from given two matrices. + pub fn mul(left: Self, right: Self) Self { + var result = Self.identity(); + for (0..result.data.len) |column| { + for (0..result.data[column].len) |row| { + var sum: T = 0; + + for (0..left.data.len) |left_column| { + sum += left.data[left_column][row] * right.data[column][left_column]; + } + + result.data[column][row] = sum; + } + } + return result; + } + + fn detsubs(self: Self) [12]T { + return .{ + self.data[0][0] * self.data[1][1] - self.data[1][0] * self.data[0][1], + self.data[0][0] * self.data[1][2] - self.data[1][0] * self.data[0][2], + self.data[0][0] * self.data[1][3] - self.data[1][0] * self.data[0][3], + self.data[0][1] * self.data[1][2] - self.data[1][1] * self.data[0][2], + self.data[0][1] * self.data[1][3] - self.data[1][1] * self.data[0][3], + self.data[0][2] * self.data[1][3] - self.data[1][2] * self.data[0][3], + + self.data[2][0] * self.data[3][1] - self.data[3][0] * self.data[2][1], + self.data[2][0] * self.data[3][2] - self.data[3][0] * self.data[2][2], + self.data[2][0] * self.data[3][3] - self.data[3][0] * self.data[2][3], + self.data[2][1] * self.data[3][2] - self.data[3][1] * self.data[2][2], + self.data[2][1] * self.data[3][3] - self.data[3][1] * self.data[2][3], + self.data[2][2] * self.data[3][3] - self.data[3][2] * self.data[2][3], + }; + } + + /// Calculate determinant of the given 4x4 matrix. + pub fn det(self: Self) T { + const s = detsubs(self); + return s[0] * s[11] - s[1] * s[10] + s[2] * s[9] + s[3] * s[8] - s[4] * s[7] + s[5] * s[6]; + } + + /// Construct inverse 4x4 from given matrix. + /// Note: This is not the most efficient way to do this. + /// TODO: Make it more efficient. + pub fn inv(self: Self) Self { + var inv_mat: Self = undefined; + + const s = detsubs(self); + + const determ = 1 / (s[0] * s[11] - s[1] * s[10] + s[2] * s[9] + s[3] * s[8] - s[4] * s[7] + s[5] * s[6]); + + inv_mat.data[0][0] = determ * (self.data[1][1] * s[11] - self.data[1][2] * s[10] + self.data[1][3] * s[9]); + inv_mat.data[0][1] = determ * -(self.data[0][1] * s[11] - self.data[0][2] * s[10] + self.data[0][3] * s[9]); + inv_mat.data[0][2] = determ * (self.data[3][1] * s[5] - self.data[3][2] * s[4] + self.data[3][3] * s[3]); + inv_mat.data[0][3] = determ * -(self.data[2][1] * s[5] - self.data[2][2] * s[4] + self.data[2][3] * s[3]); + + inv_mat.data[1][0] = determ * -(self.data[1][0] * s[11] - self.data[1][2] * s[8] + self.data[1][3] * s[7]); + inv_mat.data[1][1] = determ * (self.data[0][0] * s[11] - self.data[0][2] * s[8] + self.data[0][3] * s[7]); + inv_mat.data[1][2] = determ * -(self.data[3][0] * s[5] - self.data[3][2] * s[2] + self.data[3][3] * s[1]); + inv_mat.data[1][3] = determ * (self.data[2][0] * s[5] - self.data[2][2] * s[2] + self.data[2][3] * s[1]); + + inv_mat.data[2][0] = determ * (self.data[1][0] * s[10] - self.data[1][1] * s[8] + self.data[1][3] * s[6]); + inv_mat.data[2][1] = determ * -(self.data[0][0] * s[10] - self.data[0][1] * s[8] + self.data[0][3] * s[6]); + inv_mat.data[2][2] = determ * (self.data[3][0] * s[4] - self.data[3][1] * s[2] + self.data[3][3] * s[0]); + inv_mat.data[2][3] = determ * -(self.data[2][0] * s[4] - self.data[2][1] * s[2] + self.data[2][3] * s[0]); + + inv_mat.data[3][0] = determ * -(self.data[1][0] * s[9] - self.data[1][1] * s[7] + self.data[1][2] * s[6]); + inv_mat.data[3][1] = determ * (self.data[0][0] * s[9] - self.data[0][1] * s[7] + self.data[0][2] * s[6]); + inv_mat.data[3][2] = determ * -(self.data[3][0] * s[3] - self.data[3][1] * s[1] + self.data[3][2] * s[0]); + inv_mat.data[3][3] = determ * (self.data[2][0] * s[3] - self.data[2][1] * s[1] + self.data[2][2] * s[0]); + + return inv_mat; + } + + /// Return 4x4 matrix from given all transform components; `translation`, `rotation` and `scale`. + /// The final order is T * R * S. + /// Note: `rotation` could be `Vec3` (Euler angles) or a `quat`. + pub fn recompose(translation: Vector3, rotation: anytype, scalar: Vector3) Self { + var r = switch (@TypeOf(rotation)) { + Quaternion(T) => Quaternion(T).toMat4(rotation), + Vector3 => Self.fromEulerAngles(rotation), + else => @compileError("Recompose not implemented for " ++ @typeName(@TypeOf(rotation))), + }; + + r.data[0][0] *= scalar.x(); + r.data[0][1] *= scalar.x(); + r.data[0][2] *= scalar.x(); + r.data[1][0] *= scalar.y(); + r.data[1][1] *= scalar.y(); + r.data[1][2] *= scalar.y(); + r.data[2][0] *= scalar.z(); + r.data[2][1] *= scalar.z(); + r.data[2][2] *= scalar.z(); + + r.data[3][0] = translation.x(); + r.data[3][1] = translation.y(); + r.data[3][2] = translation.z(); + + return r; + } + + /// Return `translation`, `rotation` and `scale` components from given matrix. + /// For now, the rotation returned is a quaternion. If you want to get Euler angles + /// from it, just do: `returned_quat.extractEulerAngles()`. + /// Note: We ortho nornalize the given matrix before extracting the rotation. + pub fn decompose(self: Self) struct { t: Vector3, r: Quaternion(T), s: Vector3 } { + const t = self.extractTranslation(); + const s = self.extractScale(); + const r = Quaternion(T).fromMat4(self.orthoNormalize()); + + return .{ + .t = t, + .r = r, + .s = s, + }; + } + + /// Print the 4x4 to stderr. + pub fn debugPrint(self: Self) void { + const print = std.debug.print; + + print("({d}, {d}, {d}, {d})\n", .{ + self.data[0][0], + self.data[1][0], + self.data[2][0], + self.data[3][0], + }); + + print("({d}, {d}, {d}, {d})\n", .{ + self.data[0][1], + self.data[1][1], + self.data[2][1], + self.data[3][1], + }); + + print("({d}, {d}, {d}, {d})\n", .{ + self.data[0][2], + self.data[1][2], + self.data[2][2], + self.data[3][2], + }); + + print("({d}, {d}, {d}, {d})\n", .{ + self.data[0][3], + self.data[1][3], + self.data[2][3], + self.data[3][3], + }); + } + + /// Cast a type to another type. + /// It's like builtins: @intCast, @floatCast, @floatFromInt, @intFromFloat. + pub fn cast(self: Self, comptime dest_type: type) Mat4x4(dest_type) { + const dest_info = @typeInfo(dest_type); + + if (dest_info != .Float) { + std.debug.panic("Error, dest type should be float.\n", .{}); + } + + var result: Mat4x4(dest_type) = undefined; + for (0..result.data.len) |column| { + for (0..result.data[column].len) |row| { + result.data[column][row] = @floatCast(self.data[column][row]); + } + } + return result; + } + }; +} + +test "zalgebra.Mat4.eql" { + const a = Mat4.identity(); + const b = Mat4.identity(); + const c = Mat4.zero(); + + try expectEqual(Mat4.eql(a, b), true); + try expectEqual(Mat4.eql(a, c), false); +} + +test "zalgebra.Mat4.set" { + const a = Mat4.set(12); + const b = Mat4{ + .data = .{ + .{ 12, 12, 12, 12 }, + .{ 12, 12, 12, 12 }, + .{ 12, 12, 12, 12 }, + .{ 12, 12, 12, 12 }, + }, + }; + + try expectEqual(a, b); +} + +test "zalgebra.Mat4.negate" { + const a = Mat4{ + .data = .{ + .{ 1, 2, 3, 4 }, + .{ 5, -6, 7, 8 }, + .{ 9, 10, 11, -12 }, + .{ 13, 14, 15, 16 }, + }, + }; + const a_negated = Mat4{ + .data = .{ + .{ -1, -2, -3, -4 }, + .{ -5, 6, -7, -8 }, + .{ -9, -10, -11, 12 }, + .{ -13, -14, -15, -16 }, + }, + }; + + try expectEqual(a.negate(), a_negated); +} + +test "zalgebra.Mat4.transpose" { + const a = Mat4{ + .data = .{ + .{ 1, 2, 3, 4 }, + .{ 5, 6, 7, 8 }, + .{ 9, 10, 11, 12 }, + .{ 13, 14, 15, 16 }, + }, + }; + const b = Mat4{ + .data = .{ + .{ 1, 5, 9, 13 }, + .{ 2, 6, 10, 14 }, + .{ 3, 7, 11, 15 }, + .{ 4, 8, 12, 16 }, + }, + }; + + try expectEqual(a.transpose(), b); +} + +test "zalgebra.Mat4.fromSlice" { + const data = [_]f32{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; + const result = Mat4.fromSlice(&data); + + try expectEqual(result, Mat4.identity()); +} + +test "zalgebra.Mat4.fromTranslate" { + const a = Mat4.fromTranslate(Vec3.new(2, 3, 4)); + + try expectEqual(a, Mat4{ + .data = .{ + .{ 1, 0, 0, 0 }, + .{ 0, 1, 0, 0 }, + .{ 0, 0, 1, 0 }, + .{ 2, 3, 4, 1 }, + }, + }); +} + +test "zalgebra.Mat4.translate" { + const a = Mat4.fromTranslate(Vec3.new(2, 3, 2)); + const result = Mat4.translate(a, Vec3.new(2, 3, 4)); + + try expectEqual(result, Mat4{ + .data = .{ + .{ 1, 0, 0, 0 }, + .{ 0, 1, 0, 0 }, + .{ 0, 0, 1, 0 }, + .{ 4, 6, 6, 1 }, + }, + }); +} + +test "zalgebra.Mat4.fromScale" { + const a = Mat4.fromScale(Vec3.new(2, 3, 4)); + + try expectEqual(a, Mat4{ + .data = .{ + .{ 2, 0, 0, 0 }, + .{ 0, 3, 0, 0 }, + .{ 0, 0, 4, 0 }, + .{ 0, 0, 0, 1 }, + }, + }); +} + +test "zalgebra.Mat4.scale" { + const a = Mat4.fromScale(Vec3.new(2, 3, 4)); + const result = Mat4.scale(a, Vec3.set(2)); + + try expectEqual(result, Mat4{ + .data = .{ + .{ 4, 0, 0, 0 }, + .{ 0, 6, 0, 0 }, + .{ 0, 0, 8, 0 }, + .{ 0, 0, 0, 1 }, + }, + }); +} + +test "zalgebra.Mat4.det" { + const a: Mat4 = .{ + .data = .{ + .{ 2, 0, 0, 4 }, + .{ 0, 2, 0, 0 }, + .{ 0, 0, 2, 0 }, + .{ 4, 0, 0, 2 }, + }, + }; + + try expectEqual(a.det(), -48); +} + +test "zalgebra.Mat4.inv" { + const a: Mat4 = .{ + .data = .{ + .{ 2, 0, 0, 4 }, + .{ 0, 2, 0, 0 }, + .{ 0, 0, 2, 0 }, + .{ 4, 0, 0, 2 }, + }, + }; + + try expectEqual(a.inv(), Mat4{ + .data = .{ + .{ -0.1666666716337204, 0, 0, 0.3333333432674408 }, + .{ 0, 0.5, 0, 0 }, + .{ 0, 0, 0.5, 0 }, + .{ 0.3333333432674408, 0, 0, -0.1666666716337204 }, + }, + }); +} + +test "zalgebra.Mat4.extractTranslation" { + var a = Mat4.fromTranslate(Vec3.new(2, 3, 2)); + a = a.translate(Vec3.new(2, 3, 2)); + + try expectEqual(a.extractTranslation(), Vec3.new(4, 6, 4)); +} + +test "zalgebra.Mat4.extractEulerAngles" { + const a = Mat4.fromEulerAngles(Vec3.new(45, -5, 20)); + try expectEqual(a.extractEulerAngles(), Vec3.new(45.000003814697266, -4.99052524, 19.999998092651367)); +} + +test "zalgebra.Mat4.extractScale" { + var a = Mat4.fromScale(Vec3.new(2, 4, 8)); + a = a.scale(Vec3.new(2, 4, 8)); + + try expectEqual(a.extractScale(), Vec3.new(4, 16, 64)); +} + +test "zalgebra.Mat4.recompose" { + const result = Mat4.recompose( + Vec3.set(2), + Vec3.new(45, 5, 0), + Vec3.one(), + ); + + try expectEqual(result, Mat4{ .data = .{ + .{ 0.9961947202682495, 0, -0.08715573698282242, 0 }, + .{ 0.06162841245532036, 0.7071067690849304, 0.704416036605835, 0 }, + .{ 0.06162841245532036, -0.7071067690849304, 0.704416036605835, 0 }, + .{ 2, 2, 2, 1 }, + } }); +} + +test "zalgebra.Mat4.decompose" { + const a = Mat4.recompose( + Vec3.new(10, 5, 5), + Vec3.new(45, 5, 0), + Vec3.set(1), + ); + + const result = a.decompose(); + + try expectEqual(result.t, Vec3.new(10, 5, 5)); + try expectEqual(result.s, Vec3.set(1)); + try expectEqual(result.r.extractEulerAngles(), Vec3.new(45, 5, 0.00000010712935250012379)); +} + +test "zalgebra.Mat4.cast" { + const a = Mat4{ .data = .{ + .{ 0.9961947202682495, 0, -0.08715573698282242, 0 }, + .{ 0.06162841245532036, 0.7071067690849304, 0.704416036605835, 0 }, + .{ 0.06162841245532036, -0.7071067690849304, 0.704416036605835, 0 }, + .{ 2, 2, 2, 1 }, + } }; + const a_f64 = Mat4_f64{ .data = .{ + .{ 0.9961947202682495, 0, -0.08715573698282242, 0 }, + .{ 0.06162841245532036, 0.7071067690849304, 0.704416036605835, 0 }, + .{ 0.06162841245532036, -0.7071067690849304, 0.704416036605835, 0 }, + .{ 2, 2, 2, 1 }, + } }; + try expectEqual(a.cast(f64), a_f64); + try expectEqual(a_f64.cast(f32), a); +} diff --git a/extras/bsp/src/zalgebra/quaternion.zig b/extras/bsp/src/zalgebra/quaternion.zig new file mode 100644 index 0000000..83c5838 --- /dev/null +++ b/extras/bsp/src/zalgebra/quaternion.zig @@ -0,0 +1,539 @@ +const std = @import("std"); +const root = @import("main.zig"); +const meta = std.meta; +const generic_vector = @import("generic_vector.zig"); +const mat3 = @import("mat3.zig"); +const mat4 = @import("mat4.zig"); +const math = std.math; +const eps_value = math.floatEps(f32); +const expectApproxEqAbs = std.testing.expectApproxEqAbs; +const expectApproxEqRel = std.testing.expectApproxEqRel; +const expectEqual = std.testing.expectEqual; +const expect = std.testing.expect; +const assert = std.debug.assert; + +const GenericVector = generic_vector.GenericVector; + +const Vec3 = generic_vector.Vec3; +const Vec4 = generic_vector.Vec4; +const Mat3x3 = mat3.Mat3x3; +const Mat4x4 = mat4.Mat4x4; + +pub const Quat = Quaternion(f32); +pub const Quat_f64 = Quaternion(f64); + +/// A Quaternion for 3D rotations. +pub fn Quaternion(comptime T: type) type { + if (@typeInfo(T) != .Float) { + @compileError("Quaternion not implemented for " ++ @typeName(T)); + } + + const Vector3 = GenericVector(3, T); + + return extern struct { + w: T, + x: T, + y: T, + z: T, + + const Self = @This(); + + /// Construct new quaternion from floats. + pub fn new(w: T, x: T, y: T, z: T) Self { + return .{ + .w = w, + .x = x, + .y = y, + .z = z, + }; + } + + /// Shorthand for (1, 0, 0, 0). + pub fn identity() Self { + return Self.new(1, 0, 0, 0); + } + + /// Set all components to the same given value. + pub fn set(val: T) Self { + return Self.new(val, val, val, val); + } + + /// Construct new quaternion from slice. + /// Note: Careful, the latest component `slice[3]` is the `W` component. + pub fn fromSlice(slice: []const T) Self { + return Self.new(slice[3], slice[0], slice[1], slice[2]); + } + + // Construct new quaternion from given `W` component and Vector3. + pub fn fromVec3(w: T, axis: Vector3) Self { + return Self.new(w, axis.x(), axis.y(), axis.z()); + } + + /// Return true if two quaternions are equal. + pub fn eql(left: Self, right: Self) bool { + return meta.eql(left, right); + } + + /// Construct new normalized quaternion from a given one. + pub fn norm(self: Self) Self { + const l = length(self); + if (l == 0) { + return self; + } + return Self.new( + self.w / l, + self.x / l, + self.y / l, + self.z / l, + ); + } + + /// Return the length (magnitude) of quaternion. + pub fn length(self: Self) T { + return @sqrt(self.dot(self)); + } + + /// Substraction between two quaternions. + pub fn sub(left: Self, right: Self) Self { + return Self.new( + left.w - right.w, + left.x - right.x, + left.y - right.y, + left.z - right.z, + ); + } + + /// Addition between two quaternions. + pub fn add(left: Self, right: Self) Self { + return Self.new( + left.w + right.w, + left.x + right.x, + left.y + right.y, + left.z + right.z, + ); + } + + /// Quaternions' multiplication. + /// Produce a new quaternion from given two quaternions. + pub fn mul(left: Self, right: Self) Self { + const x = (left.x * right.w) + (left.y * right.z) - (left.z * right.y) + (left.w * right.x); + const y = (-left.x * right.z) + (left.y * right.w) + (left.z * right.x) + (left.w * right.y); + const z = (left.x * right.y) - (left.y * right.x) + (left.z * right.w) + (left.w * right.z); + const w = (-left.x * right.x) - (left.y * right.y) - (left.z * right.z) + (left.w * right.w); + + return Self.new(w, x, y, z); + } + + /// Multiply each component by the given scalar. + pub fn scale(mat: Self, scalar: T) Self { + const w = mat.w * scalar; + const x = mat.x * scalar; + const y = mat.y * scalar; + const z = mat.z * scalar; + + return Self.new(w, x, y, z); + } + + /// Negate the given quaternion + pub fn negate(self: Self) Self { + return self.scale(-1); + } + + /// Return the dot product between two quaternion. + pub fn dot(left: Self, right: Self) T { + return (left.x * right.x) + (left.y * right.y) + (left.z * right.z) + (left.w * right.w); + } + + /// Convert given quaternion to rotation 3x3 matrix. + fn toMat3(self: Self) Mat3x3(T) { + var result: Mat3x3(T) = undefined; + + const normalized = self.norm(); + const xx = normalized.x * normalized.x; + const yy = normalized.y * normalized.y; + const zz = normalized.z * normalized.z; + const xy = normalized.x * normalized.y; + const xz = normalized.x * normalized.z; + const yz = normalized.y * normalized.z; + const wx = normalized.w * normalized.x; + const wy = normalized.w * normalized.y; + const wz = normalized.w * normalized.z; + + result.data[0][0] = 1 - 2 * (yy + zz); + result.data[0][1] = 2 * (xy + wz); + result.data[0][2] = 2 * (xz - wy); + + result.data[1][0] = 2 * (xy - wz); + result.data[1][1] = 1 - 2 * (xx + zz); + result.data[1][2] = 2 * (yz + wx); + + result.data[2][0] = 2 * (xz + wy); + result.data[2][1] = 2 * (yz - wx); + result.data[2][2] = 1 - 2 * (xx + yy); + + return result; + } + + /// Convert given quaternion to rotation 4x4 matrix. + /// Mostly taken from https://github.com/HandmadeMath/Handmade-Math. + pub fn toMat4(self: Self) Mat4x4(T) { + var result: Mat4x4(T) = undefined; + + const normalized = self.norm(); + const xx = normalized.x * normalized.x; + const yy = normalized.y * normalized.y; + const zz = normalized.z * normalized.z; + const xy = normalized.x * normalized.y; + const xz = normalized.x * normalized.z; + const yz = normalized.y * normalized.z; + const wx = normalized.w * normalized.x; + const wy = normalized.w * normalized.y; + const wz = normalized.w * normalized.z; + + result.data[0][0] = 1 - 2 * (yy + zz); + result.data[0][1] = 2 * (xy + wz); + result.data[0][2] = 2 * (xz - wy); + result.data[0][3] = 0; + + result.data[1][0] = 2 * (xy - wz); + result.data[1][1] = 1 - 2 * (xx + zz); + result.data[1][2] = 2 * (yz + wx); + result.data[1][3] = 0; + + result.data[2][0] = 2 * (xz + wy); + result.data[2][1] = 2 * (yz - wx); + result.data[2][2] = 1 - 2 * (xx + yy); + result.data[2][3] = 0; + + result.data[3][0] = 0; + result.data[3][1] = 0; + result.data[3][2] = 0; + result.data[3][3] = 1; + + return result; + } + + /// From Mike Day at Insomniac Games. + /// For more details: https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2015/01/matrix-to-quat.pdf + pub fn fromMat4(mat: Mat4x4(T)) Self { + var t: T = undefined; + var result: Self = undefined; + + if (mat.data[2][2] < 0) { + if (mat.data[0][0] > mat.data[1][1]) { + t = 1 + mat.data[0][0] - mat.data[1][1] - mat.data[2][2]; + result = Self.new( + mat.data[1][2] - mat.data[2][1], + t, + mat.data[0][1] + mat.data[1][0], + mat.data[2][0] + mat.data[0][2], + ); + } else { + t = 1 - mat.data[0][0] + mat.data[1][1] - mat.data[2][2]; + result = Self.new( + mat.data[2][0] - mat.data[0][2], + mat.data[0][1] + mat.data[1][0], + t, + mat.data[1][2] + mat.data[2][1], + ); + } + } else { + if (mat.data[0][0] < -mat.data[1][1]) { + t = 1 - mat.data[0][0] - mat.data[1][1] + mat.data[2][2]; + result = Self.new( + mat.data[0][1] - mat.data[1][0], + mat.data[2][0] + mat.data[0][2], + mat.data[1][2] + mat.data[2][1], + t, + ); + } else { + t = 1 + mat.data[0][0] + mat.data[1][1] + mat.data[2][2]; + result = Self.new( + t, + mat.data[1][2] - mat.data[2][1], + mat.data[2][0] - mat.data[0][2], + mat.data[0][1] - mat.data[1][0], + ); + } + } + + return result.scale(0.5 / @sqrt(t)); + } + + /// Convert all Euler angles (in degrees) to quaternion. + pub fn fromEulerAngles(axis_in_degrees: Vector3) Self { + const x = Self.fromAxis(axis_in_degrees.x(), Vector3.right()); + const y = Self.fromAxis(axis_in_degrees.y(), Vector3.up()); + const z = Self.fromAxis(axis_in_degrees.z(), Vector3.forward()); + + return z.mul(y.mul(x)); + } + + /// Convert Euler angle around specified axis to quaternion. + pub fn fromAxis(degrees: T, axis: Vector3) Self { + const radians = root.toRadians(degrees); + + const rot_sin = @sin(radians / 2); + const quat_axis = axis.norm().data * @as(@TypeOf(axis.data), @splat(rot_sin)); + const w = @cos(radians / 2); + + return Self.fromVec3(w, .{ .data = quat_axis }); + } + + /// Extract euler angles (degrees) from quaternion. + pub fn extractEulerAngles(self: Self) Vector3 { + const yaw = math.atan2( + 2 * (self.y * self.z + self.w * self.x), + self.w * self.w - self.x * self.x - self.y * self.y + self.z * self.z, + ); + const pitch = math.asin( + -2 * (self.x * self.z - self.w * self.y), + ); + const roll = math.atan2( + 2 * (self.x * self.y + self.w * self.z), + self.w * self.w + self.x * self.x - self.y * self.y - self.z * self.z, + ); + + return Vector3.new(root.toDegrees(yaw), root.toDegrees(pitch), root.toDegrees(roll)); + } + + /// Get the rotation angle (degrees) and axis for a given quaternion. + // Taken from https://github.com/raysan5/raylib/blob/master/src/raymath.h#L1755 + pub fn extractAxisAngle(self: Self) struct { axis: Vector3, angle: T } { + var copy = self; + if (@abs(copy.w) > 1) copy = copy.norm(); + + var res_axis = Vector3.zero(); + const res_angle: T = 2 * math.acos(copy.w); + const den: T = @sqrt(1 - copy.w * copy.w); + + if (den > 0.0001) { + res_axis.data[0] = copy.x / den; + res_axis.data[1] = copy.y / den; + res_axis.data[2] = copy.z / den; + } else { + // This occurs when the angle is zero. + // Not a problem: just set an arbitrary normalized axis. + res_axis.data[0] = 1; + } + + return .{ + .axis = res_axis, + .angle = root.toDegrees(res_angle), + }; + } + + /// Construct inverse quaternion + pub fn inv(self: Self) Self { + const res = Self.new(self.w, -self.x, -self.y, -self.z); + return res.scale(1 / self.dot(self)); + } + + /// Linear interpolation between two quaternions. + pub fn lerp(left: Self, right: Self, t: T) Self { + const w = root.lerp(T, left.w, right.w, t); + const x = root.lerp(T, left.x, right.x, t); + const y = root.lerp(T, left.y, right.y, t); + const z = root.lerp(T, left.z, right.z, t); + return Self.new(w, x, y, z); + } + + // Shortest path slerp between two quaternions. + // Taken from "Physically Based Rendering, 3rd Edition, Chapter 2.9.2" + // https://pbr-book.org/3ed-2018/Geometry_and_Transformations/Animating_Transformations#QuaternionInterpolation + pub fn slerp(left: Self, right: Self, t: T) Self { + const ParallelThreshold = 0.9995; + var cos_theta = dot(left, right); + var right1 = right; + + // We need the absolute value of the dot product to take the shortest path + if (cos_theta < 0) { + cos_theta *= -1; + right1 = right.negate(); + } + + if (cos_theta > ParallelThreshold) { + // Use regular old lerp to avoid numerical instability + return lerp(left, right1, t); + } else { + const theta = math.acos(math.clamp(cos_theta, -1, 1)); + const thetap = theta * t; + var qperp = right1.sub(left.scale(cos_theta)).norm(); + return left.scale(@cos(thetap)).add(qperp.scale(@sin(thetap))); + } + } + + /// Rotate the Vector3 v using the sandwich product. + /// Taken from "Foundations of Game Engine Development Vol. 1 Mathematics". + pub fn rotateVec(self: Self, v: Vector3) Vector3 { + const q = self.norm(); + const b = Vector3.new(q.x, q.y, q.z); + const b2 = b.dot(b); + + return v.scale(q.w * q.w - b2).add(b.scale(v.dot(b) * 2)).add(b.cross(v).scale(q.w * 2)); + } + + /// Cast a type to another type. + /// It's like builtins: @intCast, @floatCast, @floatFromInt, @intFromFloat. + pub fn cast(self: Self, comptime dest_type: type) Quaternion(dest_type) { + const dest_info = @typeInfo(dest_type); + + if (dest_info != .Float) { + std.debug.panic("Error, dest type should be float.\n", .{}); + } + + const w: dest_type = @floatCast(self.w); + const x: dest_type = @floatCast(self.x); + const y: dest_type = @floatCast(self.y); + const z: dest_type = @floatCast(self.z); + return Quaternion(dest_type).new(w, x, y, z); + } + }; +} + +test "zalgebra.Quaternion.new" { + const q = Quat.new(1.5, 2.6, 3.7, 4.7); + + try expectEqual(q.w, 1.5); + try expectEqual(q.x, 2.6); + try expectEqual(q.y, 3.7); + try expectEqual(q.z, 4.7); +} + +test "zalgebra.Quaternion.set" { + const a = Quat.set(12); + const b = Quat.new(12, 12, 12, 12); + + try expectEqual(a, b); +} + +test "zalgebra.Quaternion.eql" { + const a = Quat.new(1.5, 2.6, 3.7, 4.7); + const b = Quat.new(1.5, 2.6, 3.7, 4.7); + const c = Quat.new(2.6, 3.7, 4.8, 5.9); + + try expectEqual(Quat.eql(a, b), true); + try expectEqual(Quat.eql(a, c), false); +} + +test "zalgebra.Quaternion.fromSlice" { + const array = [4]f32{ 2, 3, 4, 1 }; + try expectEqual(Quat.fromSlice(&array), Quat.new(1, 2, 3, 4)); +} + +test "zalgebra.Quaternion.fromVec3" { + const q = Quat.fromVec3(1.5, Vec3.new(2.6, 3.7, 4.7)); + + try expectEqual(q.w, 1.5); + try expectEqual(q.x, 2.6); + try expectEqual(q.y, 3.7); + try expectEqual(q.z, 4.7); + + const a = Quat.fromVec3(1.5, Vec3.new(2.6, 3.7, 4.7)); + const b = Quat.fromVec3(1.5, Vec3.new(2.6, 3.7, 4.7)); + const c = Quat.fromVec3(1, Vec3.new(2.6, 3.7, 4.7)); + + try expectEqual(a, b); + try expectEqual(Quat.eql(a, c), false); +} + +test "zalgebra.Quaternion.norm" { + const a = Quat.fromVec3(1, Vec3.new(2, 2, 2)); + const b = Quat.fromVec3(0.2773500978946686, Vec3.new(0.5547001957893372, 0.5547001957893372, 0.5547001957893372)); + + try expectEqual(a.norm(), b); +} + +test "zalgebra.Quaternion.fromEulerAngles" { + const a = Quat.fromEulerAngles(Vec3.new(10, 5, 45)); + const a_res = a.extractEulerAngles(); + + const b = Quat.fromEulerAngles(Vec3.new(0, 55, 22)); + const b_res = b.toMat4().extractEulerAngles(); + + try expectEqual(a_res, Vec3.new(9.999999046325684, 5.000000476837158, 45)); + try expectEqual(b_res, Vec3.new(0, 47.2450294, 22)); +} + +test "zalgebra.Quaternion.fromAxis" { + const q = Quat.fromAxis(45, Vec3.up()); + const res_q = q.extractEulerAngles(); + + try expectEqual(res_q, Vec3.new(0, 45.0000076, 0)); +} + +test "zalgebra.Quaternion.extractAxisAngle" { + const axis = Vec3.new(44, 120, 8).norm(); + const q = Quat.fromAxis(45, axis); + const res = q.extractAxisAngle(); + + try expectApproxEqRel(axis.x(), res.axis.x(), eps_value); + try expectApproxEqRel(axis.y(), res.axis.y(), eps_value); + try expectApproxEqRel(axis.z(), res.axis.z(), eps_value); + + try expectApproxEqRel(res.angle, 45.0000076, eps_value); +} + +test "zalgebra.Quaternion.extractEulerAngles" { + const q = Quat.fromVec3(0.5, Vec3.new(0.5, 1, 0.3)); + const res_q = q.extractEulerAngles(); + + try expectEqual(res_q, Vec3.new(129.6000213623047, 44.427005767822266, 114.4107360839843)); +} + +test "zalgebra.Quaternion.rotateVec" { + const q = Quat.fromEulerAngles(Vec3.set(45)); + const m = q.toMat4(); + + const v = Vec3.up(); + const v1 = q.rotateVec(v); + const v2 = m.mulByVec4(Vec4.new(v.x(), v.y(), v.z(), 1)); + + try expectApproxEqAbs(v1.x(), -1.46446585e-01, eps_value); + try expectApproxEqAbs(v1.y(), 8.53553473e-01, eps_value); + try expectApproxEqAbs(v1.z(), 0.5, eps_value); + + try expectApproxEqAbs(v1.x(), v2.data[0], eps_value); + try expectApproxEqAbs(v1.y(), v2.data[1], eps_value); + try expectApproxEqAbs(v1.z(), v2.data[2], eps_value); +} + +test "zalgebra.Quaternion.lerp" { + const a = Quat.identity(); + const b = Quat.fromAxis(180, Vec3.up()); + try expectEqual(Quat.lerp(a, b, 1), b); + const c = Quat.lerp(a, b, 0.5); + const d = Quat.new(0.5, 0, 0.5, 0); + try expectApproxEqAbs(c.w, d.w, eps_value); + try expectApproxEqAbs(c.x, d.x, eps_value); + try expectApproxEqAbs(c.y, d.y, eps_value); + try expectApproxEqAbs(c.z, d.z, eps_value); +} + +test "zalgebra.Quaternion.slerp" { + const a = Quat.identity(); + const b = Quat.fromAxis(180, Vec3.up()); + try expectEqual(Quat.slerp(a, b, 1), Quat.new(7.54979012e-08, 0, -1, 0)); + const c = Quat.slerp(a, b, 0.5); + const d = Quat.new(1, 0, -1, 0).norm(); + try expectApproxEqAbs(c.w, d.w, eps_value); + try expectApproxEqAbs(c.x, d.x, eps_value); + try expectApproxEqAbs(c.y, d.y, eps_value); + try expectApproxEqAbs(c.z, d.z, eps_value); +} + +test "zalgebra.Quaternion.cast" { + const a = Quat.new(3.5, 4.5, 5.5, 6.5); + const a_f64 = Quat_f64.new(3.5, 4.5, 5.5, 6.5); + try expectEqual(a.cast(f64), a_f64); + try expectEqual(a_f64.cast(f32), a); +} + +test "zalgebra.Quaternion.inv" { + const out = Quat.new(7, 4, 5, 9).inv(); + const answ = Quat.new(0.0409357, -0.0233918, -0.0292398, -0.0526316); + try expectApproxEqAbs(out.w, answ.w, eps_value); + try expectApproxEqAbs(out.x, answ.x, eps_value); + try expectApproxEqAbs(out.y, answ.y, eps_value); + try expectApproxEqAbs(out.z, answ.z, eps_value); +} diff --git a/extras/doomplayer/src/doom.zig b/extras/doomplayer/src/doom.zig index fad5491..baca6a3 100644 --- a/extras/doomplayer/src/doom.zig +++ b/extras/doomplayer/src/doom.zig @@ -20,6 +20,12 @@ pub const DoomCanvas = struct { entity: core.Entity, first: bool = false, + pub fn cleanupDoom() void { + if (gDoom) |doom| { + doom.destroy(); + } + } + pub fn create(alloc: std.mem.Allocator) !*@This() { var first: bool = false; if (gDoom == null) { @@ -57,9 +63,8 @@ pub const DoomCanvas = struct { } pub fn tick(self: *@This(), dt: f64) void { - if (self.first) { - gDoom.?.tick(dt); - } + _ = self; + _ = dt; } pub fn getEntity(self: *@This()) core.Entity { @@ -68,9 +73,6 @@ pub const DoomCanvas = struct { pub fn destroy(self: *@This()) void { self.entity.destroy(); - if (self.first) { - gDoom.?.destroy(); - } self.data.release(self); } }; @@ -440,6 +442,12 @@ pub fn createTextures(self: *@This()) !void { }); } +pub fn maybeTick(dt: f64) void { + if (gDoom) |doom| { + doom.tick(dt); + } +} + pub fn tick(self: *@This(), dt: f64) void { _ = dt; c.doom_update(); @@ -462,8 +470,8 @@ pub fn tick(self: *@This(), dt: f64) void { if (self.inputEnabled) { if (ig.begin("doom settings", null, .{})) { _ = ig.sliderFloat("sensitivity", &self.sensitivity, 0.1, 20, null, .{}); - ig.end(); } + ig.end(); } } @@ -479,7 +487,7 @@ fn bindVideoTextures(p: ?*anyopaque) void { // creates a video player entity pub fn destroy(self: *@This()) void { - core.engine_logs("[Videoplayer] destroying player"); + core.engine_logs("[Doom] destroying doom instance"); self.allocator.destroy(self); } diff --git a/extras/gameExtras/src/RendererDebug.zig b/extras/gameExtras/src/RendererDebug.zig new file mode 100644 index 0000000..1f47bc2 --- /dev/null +++ b/extras/gameExtras/src/RendererDebug.zig @@ -0,0 +1,46 @@ +dtAverage: f64 = 0.0, +allocator: std.mem.Allocator, + +pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); + +pub fn create(allocator: std.mem.Allocator) !*@This() { + const self = try allocator.create(@This()); + + self.* = .{ .allocator = allocator }; + + return self; +} + +pub fn tick(self: *@This(), dt: f64) void { + core.rollingAverage(&self.dtAverage, dt, 50); + + if (ig.begin("renderer debug", null, .{})) { + _ = ig.sliderFloat("directional light yaw", &rend.context().directionalLightYaw, 0, 360, null, .{}); + _ = ig.sliderFloat("skyboxLevel", &rend.context().skyboxSystem.brightnessFactor, 0, 10, null, .{}); + _ = ig.sliderFloat("lightLevel", &rend.context().lightPower, 0, 100, null, .{}); + _ = ig.sliderFloat("ortho near", &rend.context().shadowOrthoNear, 0, 200, null, .{}); + _ = ig.sliderFloat("ortho far", &rend.context().shadowOrthoFar, 0, 6000, null, .{}); + if (self.dtAverage > 0.000001) { + ig.textFmt("frameTime: {d:.2}ms ({d:.2}fps)", .{ self.dtAverage * 1000, @as(u32, @intFromFloat(1 / self.dtAverage)) }) catch unreachable; + } + + ig.textFmt("SSAO settings: ", .{}) catch unreachable; + + const ssao = rend.context().ssaoSystem; + _ = ig.sliderFloat("radius", &ssao.radius, 0.1, 1.0, null, .{}); + _ = ig.sliderFloat("bias", &ssao.bias, 0.0025, 1.0, null, .{}); + + _ = ig.checkbox("enable SSAO", &ssao.enable); + } + ig.end(); +} + +pub fn destroy(self: *@This()) void { + self.allocator.destroy(self); +} + +const backlog = @import("Backlog"); +const core = backlog.core; +const rend = backlog.rend; +const ig = backlog.imgui.api; +const std = @import("std"); diff --git a/extras/gameExtras/src/gameExtras.zig b/extras/gameExtras/src/gameExtras.zig index 9bc35a4..643d113 100644 --- a/extras/gameExtras/src/gameExtras.zig +++ b/extras/gameExtras/src/gameExtras.zig @@ -1,5 +1,4 @@ pub const FpCamera = @import("FpCamera.zig"); - pub const inputDebugger = @import("inputDebugger.zig"); - pub const ObjectSpawner = @import("objectSpawner.zig"); +pub const RendererDebug = @import("RendererDebug.zig"); diff --git a/extras/gameExtras/src/inputDebugger.zig b/extras/gameExtras/src/inputDebugger.zig index 9bd87f3..ad5475a 100644 --- a/extras/gameExtras/src/inputDebugger.zig +++ b/extras/gameExtras/src/inputDebugger.zig @@ -24,8 +24,8 @@ pub fn tick() void { }, } } - ig.end(); } + ig.end(); } const std = @import("std"); diff --git a/extras/gameExtras/src/objectSpawner.zig b/extras/gameExtras/src/objectSpawner.zig index 638628a..a1d8a2f 100644 --- a/extras/gameExtras/src/objectSpawner.zig +++ b/extras/gameExtras/src/objectSpawner.zig @@ -25,23 +25,44 @@ pub fn create(allocator: std.mem.Allocator) !*@This() { return self; } +pub fn objectSpawnOptions(self: *@This()) void { + for (self.spawnFuncs.items) |entry| { + if (ig.smallButton(entry.typeName.ptr)) { + if (entry.spawnFunc(self.objectList)) |new| { + const entity = new.vtable.getEntity.?(new.ptr); + if (!entry.opts.absoluteSpawnposition) { + self.prepareEntity(entity); + } + } + } + } +} + +fn spawnedObjectsList(self: *@This()) void { + for (self.objectList.objects.items, 0..) |interface, i| { + ig.textFmt("{s}", .{interface.vtable.objectName}) catch {}; + ig.sameLine(0.0, 2.0); + + ig.pushID_Int(@intCast(i)); + if (ig.smallButton("delete me")) { + interface.vtable.destroy(interface.ptr); + } + ig.popID(); + } +} + pub fn tick(self: *@This(), dt: f64) void { self.objectList.tick(dt); if (self.windowOpen) { if (ig.begin("object Spawner", null, .{})) { - for (self.spawnFuncs.items) |entry| { - if (ig.smallButton(entry.typeName.ptr)) { - if (entry.spawnFunc(self.objectList)) |new| { - const entity = new.vtable.getEntity.?(new.ptr); - if (!entry.opts.absoluteSpawnposition) { - self.prepareEntity(entity); - } - } - } - } - ig.end(); + self.objectSpawnOptions(); } + ig.end(); + if (ig.begin("objects in scene", null, .{})) { + self.spawnedObjectsList(); + } + ig.end(); } } diff --git a/extras/videoplayer/src/videoplayer.zig b/extras/videoplayer/src/videoplayer.zig index 8067c4f..f85f136 100644 --- a/extras/videoplayer/src/videoplayer.zig +++ b/extras/videoplayer/src/videoplayer.zig @@ -226,11 +226,6 @@ pub fn tick(self: *@This(), dt: f64) void { self.currentFrame = thisFrame; } - - if (ig.begin("videoPlayer", &self.showDebug, .{})) { - ig.textFmt("video frame: {d}", .{self.currentFrame}) catch unreachable; - ig.end(); - } } fn bindVideoTextures(p: ?*anyopaque) void { diff --git a/lib/cimgui/src/cimgui.zig b/lib/cimgui/src/cimgui.zig index 479b384..c1778e4 100644 --- a/lib/cimgui/src/cimgui.zig +++ b/lib/cimgui/src/cimgui.zig @@ -345,12 +345,13 @@ pub const HoveredFlags = packed struct(c_int) { }; pub const DockNodeFlags = packed struct(c_int) { keep_alive_only: bool = false, // ImGuiDockNodeFlags_KeepAliveOnly = 1 << 0, + pad0: bool = false, no_docking_in_central_node: bool = false, // ImGuiDockNodeFlags_NoDockingInCentralNode = 1 << 2, passthru_central_node: bool = false, // ImGuiDockNodeFlags_PassthruCentralNode = 1 << 3, no_split: bool = false, // ImGuiDockNodeFlags_NoSplit = 1 << 4, no_resize: bool = false, // ImGuiDockNodeFlags_NoResize = 1 << 5, auto_hide_tab_bar: bool = false, // ImGuiDockNodeFlags_AutoHideTabBar = 1 << 6 - reserved: u26 = 0, // reserved, don't use + reserved: u25 = 0, // reserved, don't use }; pub const DragDropFlags = packed struct(c_int) { source_no_preview_tooltip: bool = false, // ImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0, @@ -3002,7 +3003,7 @@ pub inline fn dockSpace(id: ID, size: Vec2, flags: DockNodeFlags, window_class: return c.igDockSpace(id, @bitCast(size), @bitCast(flags), @ptrCast(window_class)); } pub inline fn dockSpaceOverViewport(viewport: [*c]const Viewport, flags: DockNodeFlags, window_class: [*c]const WindowClass) ID { //igDockSpaceOverViewport - return c.igDockSpaceOverViewport(viewport, @bitCast(flags), @ptrCast(window_class)); + return c.igDockSpaceOverViewport(getWindowDockID(), @ptrCast(viewport), @bitCast(flags), @ptrCast(window_class)); } pub inline fn setNextWindowDockID(dock_id: ID, cond: Cond) void { //igSetNextWindowDockID c.igSetNextWindowDockID(dock_id, @bitCast(cond)); diff --git a/projects/build.zig b/projects/build.zig index bc41a45..9d458ff 100644 --- a/projects/build.zig +++ b/projects/build.zig @@ -20,4 +20,5 @@ pub fn build(b: *std.Build) void { blbuild.addExtraModule(sampleGame, "gameExtras"); blbuild.addExtraModule(sampleGame, "videoplayer"); blbuild.addExtraModule(sampleGame, "doomplayer"); + blbuild.addExtraModule(sampleGame, "bsp"); } diff --git a/projects/build.zig.zon b/projects/build.zig.zon index 3eb342f..9c43814 100644 --- a/projects/build.zig.zon +++ b/projects/build.zig.zon @@ -17,6 +17,7 @@ .gameExtras = .{.path = "../extras/gameExtras"}, .videoplayer = .{.path = "../extras/videoplayer"}, .doomplayer = .{.path = "../extras/doomplayer"}, + .bsp = .{.path = "../extras/bsp"}, }, .paths = .{ "", diff --git a/projects/content/bsp/autosave/testmap.1.map b/projects/content/bsp/autosave/testmap.1.map new file mode 100644 index 0000000..520e1db --- /dev/null +++ b/projects/content/bsp/autosave/testmap.1.map @@ -0,0 +1,115 @@ +// Game: Deathwish +// Format: Standard +// entity 0 +{ +"classname" "worldspawn" +// brush 0 +{ +( -288 -144 -16 ) ( -288 -143 -16 ) ( -288 -144 -15 ) mapping_defaults/ProtoDark 64 0 0 0.25 0.25 +( -128 -240 -16 ) ( -128 -240 -15 ) ( -127 -240 -16 ) mapping_defaults/ProtoDark 0 0 0 0.25 0.25 +( -128 -144 -16 ) ( -127 -144 -16 ) ( -128 -143 -16 ) mapping_defaults/ProtoDark 0 -64 0 0.25 0.25 +( 0 -16 16 ) ( 0 -15 16 ) ( 1 -16 16 ) mapping_defaults/ProtoDark 0 -64 0 0.25 0.25 +( 0 352 16 ) ( 1 352 16 ) ( 0 352 17 ) mapping_defaults/ProtoDark 0 0 0 0.25 0.25 +( 384 -16 16 ) ( 384 -16 17 ) ( 384 -15 16 ) mapping_defaults/ProtoDark 64 0 0 0.25 0.25 +} +// brush 1 +{ +( 80 -80 16 ) ( 80 -79 16 ) ( 80 -80 17 ) mapping_defaults/ProtoOrange 64 0 0 0.25 0.25 +( 80 -80 16 ) ( 80 -80 17 ) ( 81 -80 16 ) mapping_defaults/ProtoOrange 0 0 0 0.25 0.25 +( 80 -80 16 ) ( 81 -80 16 ) ( 80 -79 16 ) mapping_defaults/ProtoOrange 0 -64 0 0.25 0.25 +( 176 -64 96 ) ( 176 -63 96 ) ( 177 -64 96 ) mapping_defaults/ProtoOrange 0 -64 0 0.25 0.25 +( 176 -64 32 ) ( 177 -64 32 ) ( 176 -64 33 ) mapping_defaults/ProtoOrange 0 0 0 0.25 0.25 +( 176 -64 32 ) ( 176 -64 33 ) ( 176 -63 32 ) mapping_defaults/ProtoOrange 64 0 0 0.25 0.25 +} +// brush 2 +{ +( 80 -32 16 ) ( 80 -31 16 ) ( 80 -32 17 ) mapping_defaults/ProtoDarkBlue 80 0 0 1 1 +( 80 -32 16 ) ( 80 -32 17 ) ( 81 -32 16 ) mapping_defaults/ProtoDarkBlue 64 0 0 1 1 +( 80 -32 16 ) ( 81 -32 16 ) ( 80 -31 16 ) mapping_defaults/ProtoDarkBlue 64 -80 0 1 1 +( 96 80 80 ) ( 96 81 80 ) ( 97 80 80 ) mapping_defaults/ProtoDarkBlue 64 -80 0 1 1 +( 96 80 32 ) ( 97 80 32 ) ( 96 80 33 ) mapping_defaults/ProtoDarkBlue 64 0 0 1 1 +( 96 80 32 ) ( 96 80 33 ) ( 96 81 32 ) mapping_defaults/ProtoDarkBlue 80 0 0 1 1 +} +// brush 3 +{ +( -160 -128 16 ) ( -160 -127 16 ) ( -160 -128 17 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +( -160 -128 16 ) ( -160 -128 17 ) ( -159 -128 16 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -160 -128 16 ) ( -159 -128 16 ) ( -160 -127 16 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -128 0 96 ) ( -128 1 96 ) ( -127 0 96 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -128 0 32 ) ( -127 0 32 ) ( -128 0 33 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -128 0 32 ) ( -128 0 33 ) ( -128 1 32 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +} +// brush 4 +{ +( -224 48 16 ) ( -224 49 16 ) ( -224 48 17 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +( -224 48 16 ) ( -224 48 17 ) ( -223 48 16 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -224 48 16 ) ( -223 48 16 ) ( -224 49 16 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -160 128 112 ) ( -160 129 112 ) ( -159 128 112 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -160 128 32 ) ( -159 128 32 ) ( -160 128 33 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -160 128 32 ) ( -160 128 33 ) ( -160 129 32 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +} +// brush 5 +{ +( -112 224 16 ) ( -112 225 16 ) ( -112 224 17 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +( -112 224 16 ) ( -112 224 17 ) ( -111 224 16 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -112 224 16 ) ( -111 224 16 ) ( -112 225 16 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -64 304 192 ) ( -64 305 192 ) ( -63 304 192 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -64 304 32 ) ( -63 304 32 ) ( -64 304 33 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -64 304 32 ) ( -64 304 33 ) ( -64 305 32 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +} +// brush 6 +{ +( 0 176 16 ) ( 0 177 16 ) ( 0 176 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 0 176 16 ) ( 0 176 17 ) ( 1 176 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 0 176 16 ) ( 1 176 16 ) ( 0 177 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 336 208 ) ( 176 337 208 ) ( 177 336 208 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 336 32 ) ( 177 336 32 ) ( 176 336 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 336 32 ) ( 176 336 33 ) ( 176 337 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 7 +{ +( 288 -32 16 ) ( 288 -31 16 ) ( 288 -32 17 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 -32 16 ) ( 288 -32 17 ) ( 289 -32 16 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 -32 16 ) ( 289 -32 16 ) ( 288 -31 16 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 336 112 176 ) ( 336 113 176 ) ( 337 112 176 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 336 112 32 ) ( 337 112 32 ) ( 336 112 33 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 336 112 32 ) ( 336 112 33 ) ( 336 113 32 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +} +// brush 8 +{ +( 208 -192 16 ) ( 208 -191 16 ) ( 208 -192 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 208 -192 16 ) ( 208 -192 17 ) ( 209 -192 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 208 -192 16 ) ( 209 -192 16 ) ( 208 -191 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -128 144 ) ( 288 -127 144 ) ( 289 -128 144 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -128 32 ) ( 289 -128 32 ) ( 288 -128 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -128 32 ) ( 288 -128 33 ) ( 288 -127 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 9 +{ +( 416 -112 16 ) ( 416 -111 16 ) ( 416 -112 17 ) mapping_defaults/ProtoDarkGreen 128 0 0 0.25 0.25 +( 416 -112 16 ) ( 416 -112 17 ) ( 417 -112 16 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 416 -112 16 ) ( 417 -112 16 ) ( 416 -111 16 ) mapping_defaults/ProtoDarkGreen -64 -128 0 0.25 0.25 +( 560 0 240 ) ( 560 1 240 ) ( 561 0 240 ) mapping_defaults/ProtoDarkGreen -64 -128 0 0.25 0.25 +( 560 0 32 ) ( 561 0 32 ) ( 560 0 33 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 560 0 32 ) ( 560 0 33 ) ( 560 1 32 ) mapping_defaults/ProtoDarkGreen 128 0 0 0.25 0.25 +} +// brush 10 +{ +( 352 224 16 ) ( 352 225 16 ) ( 352 224 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 352 224 16 ) ( 352 224 17 ) ( 353 224 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 352 224 16 ) ( 353 224 16 ) ( 352 225 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 512 288 208 ) ( 512 289 208 ) ( 513 288 208 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 512 288 32 ) ( 513 288 32 ) ( 512 288 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 512 288 32 ) ( 512 288 33 ) ( 512 289 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +} +// entity 1 +{ +"classname" "enemy_spawn" +"origin" "-64 -48 40" +} +// entity 2 +{ +"classname" "info_player_start" +"origin" "-96 128 40" +} diff --git a/projects/content/bsp/autosave/testmap.2.map b/projects/content/bsp/autosave/testmap.2.map new file mode 100644 index 0000000..7c5fada --- /dev/null +++ b/projects/content/bsp/autosave/testmap.2.map @@ -0,0 +1,187 @@ +// Game: Deathwish +// Format: Standard +// entity 0 +{ +"classname" "worldspawn" +// brush 0 +{ +( -288 -144 -16 ) ( -288 -143 -16 ) ( -288 -144 -15 ) mapping_defaults/ProtoDark 64 0 0 0.25 0.25 +( -128 -240 -16 ) ( -128 -240 -15 ) ( -127 -240 -16 ) mapping_defaults/ProtoDark 0 0 0 0.25 0.25 +( -128 -144 -16 ) ( -127 -144 -16 ) ( -128 -143 -16 ) mapping_defaults/ProtoDark 0 -64 0 0.25 0.25 +( 0 -16 16 ) ( 0 -15 16 ) ( 1 -16 16 ) mapping_defaults/ProtoDark 0 -64 0 0.25 0.25 +( 0 352 16 ) ( 1 352 16 ) ( 0 352 17 ) mapping_defaults/ProtoDark 0 0 0 0.25 0.25 +( 384 -16 16 ) ( 384 -16 17 ) ( 384 -15 16 ) mapping_defaults/ProtoDark 64 0 0 0.25 0.25 +} +// brush 1 +{ +( 80 -80 16 ) ( 80 -79 16 ) ( 80 -80 17 ) mapping_defaults/ProtoOrange 64 0 0 0.25 0.25 +( 80 -80 16 ) ( 80 -80 17 ) ( 81 -80 16 ) mapping_defaults/ProtoOrange 0 0 0 0.25 0.25 +( 80 -80 16 ) ( 81 -80 16 ) ( 80 -79 16 ) mapping_defaults/ProtoOrange 0 -64 0 0.25 0.25 +( 176 -64 96 ) ( 176 -63 96 ) ( 177 -64 96 ) mapping_defaults/ProtoOrange 0 -64 0 0.25 0.25 +( 176 -64 32 ) ( 177 -64 32 ) ( 176 -64 33 ) mapping_defaults/ProtoOrange 0 0 0 0.25 0.25 +( 176 -64 32 ) ( 176 -64 33 ) ( 176 -63 32 ) mapping_defaults/ProtoOrange 64 0 0 0.25 0.25 +} +// brush 2 +{ +( 80 -32 16 ) ( 80 -31 16 ) ( 80 -32 17 ) mapping_defaults/ProtoDarkBlue 80 0 0 1 1 +( 80 -32 16 ) ( 80 -32 17 ) ( 81 -32 16 ) mapping_defaults/ProtoDarkBlue 64 0 0 1 1 +( 80 -32 16 ) ( 81 -32 16 ) ( 80 -31 16 ) mapping_defaults/ProtoDarkBlue 64 -80 0 1 1 +( 96 80 80 ) ( 96 81 80 ) ( 97 80 80 ) mapping_defaults/ProtoDarkBlue 64 -80 0 1 1 +( 96 80 32 ) ( 97 80 32 ) ( 96 80 33 ) mapping_defaults/ProtoDarkBlue 64 0 0 1 1 +( 96 80 32 ) ( 96 80 33 ) ( 96 81 32 ) mapping_defaults/ProtoDarkBlue 80 0 0 1 1 +} +// brush 3 +{ +( -160 -128 16 ) ( -160 -127 16 ) ( -160 -128 17 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +( -160 -128 16 ) ( -160 -128 17 ) ( -159 -128 16 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -160 -128 16 ) ( -159 -128 16 ) ( -160 -127 16 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -128 0 96 ) ( -128 1 96 ) ( -127 0 96 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -128 0 32 ) ( -127 0 32 ) ( -128 0 33 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -128 0 32 ) ( -128 0 33 ) ( -128 1 32 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +} +// brush 4 +{ +( -224 48 16 ) ( -224 49 16 ) ( -224 48 17 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +( -224 48 16 ) ( -224 48 17 ) ( -223 48 16 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -224 48 16 ) ( -223 48 16 ) ( -224 49 16 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -160 128 112 ) ( -160 129 112 ) ( -159 128 112 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -160 128 32 ) ( -159 128 32 ) ( -160 128 33 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -160 128 32 ) ( -160 128 33 ) ( -160 129 32 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +} +// brush 5 +{ +( -112 224 16 ) ( -112 225 16 ) ( -112 224 17 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +( -112 224 16 ) ( -112 224 17 ) ( -111 224 16 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -112 224 16 ) ( -111 224 16 ) ( -112 225 16 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -64 304 192 ) ( -64 305 192 ) ( -63 304 192 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -64 304 32 ) ( -63 304 32 ) ( -64 304 33 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -64 304 32 ) ( -64 304 33 ) ( -64 305 32 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +} +// brush 6 +{ +( 0 176 16 ) ( 0 177 16 ) ( 0 176 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 0 176 16 ) ( 0 176 17 ) ( 1 176 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 0 176 16 ) ( 1 176 16 ) ( 0 177 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 336 208 ) ( 176 337 208 ) ( 177 336 208 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 336 32 ) ( 177 336 32 ) ( 176 336 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 336 32 ) ( 176 336 33 ) ( 176 337 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 7 +{ +( 208 -192 16 ) ( 208 -191 16 ) ( 208 -192 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 208 -192 16 ) ( 208 -192 17 ) ( 209 -192 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 208 -192 16 ) ( 209 -192 16 ) ( 208 -191 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -128 144 ) ( 288 -127 144 ) ( 289 -128 144 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -128 32 ) ( 289 -128 32 ) ( 288 -128 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -128 32 ) ( 288 -128 33 ) ( 288 -127 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 8 +{ +( 416 -112 16 ) ( 416 -111 16 ) ( 416 -112 17 ) mapping_defaults/ProtoDarkGreen 128 0 0 0.25 0.25 +( 416 -112 16 ) ( 416 -112 17 ) ( 417 -112 16 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 416 -112 16 ) ( 417 -112 16 ) ( 416 -111 16 ) mapping_defaults/ProtoDarkGreen -64 -128 0 0.25 0.25 +( 560 0 240 ) ( 560 1 240 ) ( 561 0 240 ) mapping_defaults/ProtoDarkGreen -64 -128 0 0.25 0.25 +( 560 0 32 ) ( 561 0 32 ) ( 560 0 33 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 560 0 32 ) ( 560 0 33 ) ( 560 1 32 ) mapping_defaults/ProtoDarkGreen 128 0 0 0.25 0.25 +} +// brush 9 +{ +( 352 224 16 ) ( 352 225 16 ) ( 352 224 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 352 224 16 ) ( 352 224 17 ) ( 353 224 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 352 224 16 ) ( 353 224 16 ) ( 352 225 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 512 288 208 ) ( 512 289 208 ) ( 513 288 208 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 512 288 32 ) ( 513 288 32 ) ( 512 288 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 512 288 32 ) ( 512 288 33 ) ( 512 289 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 10 +{ +( -16 -304 16 ) ( -16 -303 16 ) ( -16 -304 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -16 -304 16 ) ( -16 -304 17 ) ( -15 -304 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -16 -304 16 ) ( -15 -304 16 ) ( -16 -303 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 16 -128 240 ) ( 16 -127 240 ) ( 17 -128 240 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 16 -128 32 ) ( 17 -128 32 ) ( 16 -128 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 16 -128 32 ) ( 16 -128 33 ) ( 16 -127 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 11 +{ +( -272 -288 16 ) ( -272 -287 16 ) ( -272 -288 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -272 -288 16 ) ( -272 -288 17 ) ( -271 -288 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -272 -288 16 ) ( -271 -288 16 ) ( -272 -287 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -176 -80 32 ) ( -176 -79 32 ) ( -175 -80 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -176 -80 32 ) ( -175 -80 32 ) ( -176 -80 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -176 -80 32 ) ( -176 -80 33 ) ( -176 -79 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 12 +{ +( -96 -432 16 ) ( -96 -431 16 ) ( -96 -432 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -96 -432 16 ) ( -96 -432 17 ) ( -95 -432 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -96 -432 16 ) ( -95 -432 16 ) ( -96 -431 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -64 -192 432 ) ( -64 -191 432 ) ( -63 -192 432 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -64 -192 32 ) ( -63 -192 32 ) ( -64 -192 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -64 -192 32 ) ( -64 -192 33 ) ( -64 -191 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 13 +{ +( 304 16 96 ) ( 304 17 96 ) ( 304 16 97 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 304 16 96 ) ( 304 16 97 ) ( 305 16 96 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 304 16 96 ) ( 305 16 96 ) ( 304 17 96 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 320 48 112 ) ( 320 49 112 ) ( 321 48 112 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 320 48 112 ) ( 321 48 112 ) ( 320 48 113 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 320 48 112 ) ( 320 48 113 ) ( 320 49 112 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 14 +{ +( 256 -48 128 ) ( 256 -47 128 ) ( 256 -48 129 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -48 128 ) ( 288 -48 129 ) ( 289 -48 128 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -48 128 ) ( 289 -48 128 ) ( 288 -47 128 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 304 0 144 ) ( 304 1 144 ) ( 305 0 144 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 304 64 144 ) ( 305 64 144 ) ( 304 64 145 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 304 0 144 ) ( 304 0 145 ) ( 304 1 144 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 15 +{ +( 288 -32 16 ) ( 288 -31 16 ) ( 288 -32 17 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 -32 16 ) ( 288 -32 17 ) ( 289 -32 16 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 16 96 ) ( 288 0 112 ) ( 416 0 112 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 336 112 176 ) ( 336 113 176 ) ( 337 112 176 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 80 128 ) ( 288 32 96 ) ( 416 32 96 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 336 112 32 ) ( 337 112 32 ) ( 336 112 33 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 336 112 32 ) ( 336 112 33 ) ( 336 113 32 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +} +// brush 16 +{ +( 272 -32 16 ) ( 272 -31 16 ) ( 272 -32 17 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 -32 16 ) ( 288 -32 17 ) ( 289 -32 16 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 80 128 ) ( 288 32 96 ) ( 416 32 96 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 16 96 ) ( 416 0 112 ) ( 288 0 112 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 336 112 32 ) ( 336 112 33 ) ( 336 113 32 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +} +// brush 17 +{ +( 160 32 16 ) ( 160 33 16 ) ( 160 32 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 160 32 16 ) ( 160 32 17 ) ( 161 32 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 160 32 16 ) ( 161 32 16 ) ( 160 33 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 128 112 ) ( 176 129 112 ) ( 177 128 112 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 128 32 ) ( 177 128 32 ) ( 176 128 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 128 32 ) ( 176 128 33 ) ( 176 129 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 18 +{ +( 256 16 16 ) ( 256 17 16 ) ( 256 16 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 256 16 16 ) ( 256 16 17 ) ( 257 16 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 256 16 16 ) ( 257 16 16 ) ( 256 17 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 272 128 112 ) ( 272 129 112 ) ( 273 128 112 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 272 128 32 ) ( 273 128 32 ) ( 272 128 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 272 128 32 ) ( 272 128 33 ) ( 272 129 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +} +// entity 1 +{ +"classname" "enemy_spawn" +"origin" "-64 -48 40" +} +// entity 2 +{ +"classname" "info_player_start" +"origin" "-96 128 40" +} diff --git a/projects/content/bsp/autosave/testmap.3.map b/projects/content/bsp/autosave/testmap.3.map new file mode 100644 index 0000000..3cbea41 --- /dev/null +++ b/projects/content/bsp/autosave/testmap.3.map @@ -0,0 +1,821 @@ +// Game: Deathwish +// Format: Standard +// entity 0 +{ +"classname" "worldspawn" +// brush 0 +{ +( -288 -144 -16 ) ( -288 -143 -16 ) ( -288 -144 -15 ) mapping_defaults/ProtoDark 64 0 0 0.25 0.25 +( -128 -240 -16 ) ( -128 -240 -15 ) ( -127 -240 -16 ) mapping_defaults/ProtoDark 0 0 0 0.25 0.25 +( -128 -144 -16 ) ( -127 -144 -16 ) ( -128 -143 -16 ) mapping_defaults/ProtoDark 0 -64 0 0.25 0.25 +( 0 -16 16 ) ( 0 -15 16 ) ( 1 -16 16 ) mapping_defaults/ProtoDark 0 -64 0 0.25 0.25 +( 0 1456 16 ) ( 1 1456 16 ) ( 0 1456 17 ) mapping_defaults/ProtoDark 0 0 0 0.25 0.25 +( 1328 -16 16 ) ( 1328 -16 17 ) ( 1328 -15 16 ) mapping_defaults/ProtoDark 64 0 0 0.25 0.25 +} +// brush 1 +{ +( 80 -80 16 ) ( 80 -79 16 ) ( 80 -80 17 ) mapping_defaults/ProtoOrange 64 0 0 0.25 0.25 +( 80 -80 16 ) ( 80 -80 17 ) ( 81 -80 16 ) mapping_defaults/ProtoOrange 0 0 0 0.25 0.25 +( 80 -80 16 ) ( 81 -80 16 ) ( 80 -79 16 ) mapping_defaults/ProtoOrange 0 -64 0 0.25 0.25 +( 176 -64 96 ) ( 176 -63 96 ) ( 177 -64 96 ) mapping_defaults/ProtoOrange 0 -64 0 0.25 0.25 +( 176 -64 32 ) ( 177 -64 32 ) ( 176 -64 33 ) mapping_defaults/ProtoOrange 0 0 0 0.25 0.25 +( 176 -64 32 ) ( 176 -64 33 ) ( 176 -63 32 ) mapping_defaults/ProtoOrange 64 0 0 0.25 0.25 +} +// brush 2 +{ +( 80 -32 16 ) ( 80 -31 16 ) ( 80 -32 17 ) mapping_defaults/ProtoDarkBlue 80 0 0 1 1 +( 80 -32 16 ) ( 80 -32 17 ) ( 81 -32 16 ) mapping_defaults/ProtoDarkBlue 64 0 0 1 1 +( 80 -32 16 ) ( 81 -32 16 ) ( 80 -31 16 ) mapping_defaults/ProtoDarkBlue 64 -80 0 1 1 +( 96 80 80 ) ( 96 81 80 ) ( 97 80 80 ) mapping_defaults/ProtoDarkBlue 64 -80 0 1 1 +( 96 80 32 ) ( 97 80 32 ) ( 96 80 33 ) mapping_defaults/ProtoDarkBlue 64 0 0 1 1 +( 96 80 32 ) ( 96 80 33 ) ( 96 81 32 ) mapping_defaults/ProtoDarkBlue 80 0 0 1 1 +} +// brush 3 +{ +( -160 -128 16 ) ( -160 -127 16 ) ( -160 -128 17 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +( -160 -128 16 ) ( -160 -128 17 ) ( -159 -128 16 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -160 -128 16 ) ( -159 -128 16 ) ( -160 -127 16 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -128 0 96 ) ( -128 1 96 ) ( -127 0 96 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -128 0 32 ) ( -127 0 32 ) ( -128 0 33 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -128 0 32 ) ( -128 0 33 ) ( -128 1 32 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +} +// brush 4 +{ +( -224 48 16 ) ( -224 49 16 ) ( -224 48 17 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +( -224 48 16 ) ( -224 48 17 ) ( -223 48 16 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -224 48 16 ) ( -223 48 16 ) ( -224 49 16 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -160 128 112 ) ( -160 129 112 ) ( -159 128 112 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -160 128 32 ) ( -159 128 32 ) ( -160 128 33 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -160 128 32 ) ( -160 128 33 ) ( -160 129 32 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +} +// brush 5 +{ +( -112 224 16 ) ( -112 225 16 ) ( -112 224 17 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +( -112 224 16 ) ( -112 224 17 ) ( -111 224 16 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -112 224 16 ) ( -111 224 16 ) ( -112 225 16 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -64 304 192 ) ( -64 305 192 ) ( -63 304 192 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -64 304 32 ) ( -63 304 32 ) ( -64 304 33 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -64 304 32 ) ( -64 304 33 ) ( -64 305 32 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +} +// brush 6 +{ +( 208 -192 16 ) ( 208 -191 16 ) ( 208 -192 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 208 -192 16 ) ( 208 -192 17 ) ( 209 -192 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 208 -192 16 ) ( 209 -192 16 ) ( 208 -191 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -128 144 ) ( 288 -127 144 ) ( 289 -128 144 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -128 32 ) ( 289 -128 32 ) ( 288 -128 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -128 32 ) ( 288 -128 33 ) ( 288 -127 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 7 +{ +( 416 -112 16 ) ( 416 -111 16 ) ( 416 -112 17 ) mapping_defaults/ProtoDarkGreen 128 0 0 0.25 0.25 +( 416 -112 16 ) ( 416 -112 17 ) ( 417 -112 16 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 416 -112 16 ) ( 417 -112 16 ) ( 416 -111 16 ) mapping_defaults/ProtoDarkGreen -64 -128 0 0.25 0.25 +( 560 0 144 ) ( 560 1 144 ) ( 561 0 144 ) mapping_defaults/ProtoDarkGreen -64 -128 0 0.25 0.25 +( 560 0 32 ) ( 561 0 32 ) ( 560 0 33 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 560 0 32 ) ( 560 0 33 ) ( 560 1 32 ) mapping_defaults/ProtoDarkGreen 128 0 0 0.25 0.25 +} +// brush 8 +{ +( 352 224 16 ) ( 352 225 16 ) ( 352 224 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 352 224 16 ) ( 352 224 17 ) ( 353 224 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 352 224 16 ) ( 353 224 16 ) ( 352 225 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 512 288 208 ) ( 512 289 208 ) ( 513 288 208 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 512 288 32 ) ( 513 288 32 ) ( 512 288 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 512 288 32 ) ( 512 288 33 ) ( 512 289 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 9 +{ +( -272 -288 16 ) ( -272 -287 16 ) ( -272 -288 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -272 -288 16 ) ( -272 -288 17 ) ( -271 -288 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -272 -288 16 ) ( -271 -288 16 ) ( -272 -287 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -176 -80 32 ) ( -176 -79 32 ) ( -175 -80 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -176 -80 32 ) ( -175 -80 32 ) ( -176 -80 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -176 -80 32 ) ( -176 -80 33 ) ( -176 -79 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 10 +{ +( 304 16 96 ) ( 304 17 96 ) ( 304 16 97 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 304 16 96 ) ( 304 16 97 ) ( 305 16 96 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 304 16 96 ) ( 305 16 96 ) ( 304 17 96 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 320 48 112 ) ( 320 49 112 ) ( 321 48 112 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 320 48 112 ) ( 321 48 112 ) ( 320 48 113 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 320 48 112 ) ( 320 48 113 ) ( 320 49 112 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 11 +{ +( 256 -48 128 ) ( 256 -47 128 ) ( 256 -48 129 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -48 128 ) ( 288 -48 129 ) ( 289 -48 128 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -48 128 ) ( 289 -48 128 ) ( 288 -47 128 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 304 0 144 ) ( 304 1 144 ) ( 305 0 144 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 304 64 144 ) ( 305 64 144 ) ( 304 64 145 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 304 0 144 ) ( 304 0 145 ) ( 304 1 144 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 12 +{ +( 288 -32 16 ) ( 288 -31 16 ) ( 288 -32 17 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 -32 16 ) ( 288 -32 17 ) ( 289 -32 16 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 16 96 ) ( 288 0 112 ) ( 416 0 112 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 336 112 416 ) ( 336 113 416 ) ( 337 112 416 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 80 128 ) ( 288 32 96 ) ( 416 32 96 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 336 112 32 ) ( 337 112 32 ) ( 336 112 33 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 336 112 32 ) ( 336 112 33 ) ( 336 113 32 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +} +// brush 13 +{ +( 272 -32 16 ) ( 272 -31 16 ) ( 272 -32 17 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 -32 16 ) ( 288 -32 17 ) ( 289 -32 16 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 80 128 ) ( 288 32 96 ) ( 416 32 96 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 16 96 ) ( 416 0 112 ) ( 288 0 112 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 336 112 32 ) ( 336 112 33 ) ( 336 113 32 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +} +// brush 14 +{ +( 160 32 16 ) ( 160 33 16 ) ( 160 32 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 160 32 16 ) ( 160 32 17 ) ( 161 32 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 160 32 16 ) ( 161 32 16 ) ( 160 33 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 128 112 ) ( 176 129 112 ) ( 177 128 112 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 128 32 ) ( 177 128 32 ) ( 176 128 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 128 32 ) ( 176 128 33 ) ( 176 129 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 15 +{ +( 256 16 16 ) ( 256 17 16 ) ( 256 16 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 256 16 16 ) ( 256 16 17 ) ( 257 16 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 256 16 16 ) ( 257 16 16 ) ( 256 17 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 272 128 112 ) ( 272 129 112 ) ( 273 128 112 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 272 128 32 ) ( 273 128 32 ) ( 272 128 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 272 128 32 ) ( 272 128 33 ) ( 272 129 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 16 +{ +( 112 -176 80 ) ( 112 -176 64 ) ( 112 -48 64 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 96 -208 16 ) ( 96 -208 17 ) ( 97 -208 16 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 96 -208 16 ) ( 97 -208 16 ) ( 96 -207 16 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 176 -176 64 ) ( 176 -175 64 ) ( 177 -176 64 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 176 -176 32 ) ( 177 -176 32 ) ( 176 -176 33 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 144 -176 48 ) ( 144 -176 80 ) ( 144 -48 80 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +} +// brush 17 +{ +( 144 -176 48 ) ( 144 -48 80 ) ( 144 -176 80 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 96 -208 16 ) ( 96 -208 17 ) ( 97 -208 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 96 -208 16 ) ( 97 -208 16 ) ( 96 -207 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 -176 128 ) ( 176 -175 128 ) ( 177 -176 128 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 -176 32 ) ( 177 -176 32 ) ( 176 -176 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 -176 32 ) ( 176 -176 33 ) ( 176 -175 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 18 +{ +( 96 -208 16 ) ( 96 -207 16 ) ( 96 -208 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 96 -208 16 ) ( 96 -208 17 ) ( 97 -208 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 96 -208 16 ) ( 97 -208 16 ) ( 96 -207 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 -176 128 ) ( 176 -175 128 ) ( 177 -176 128 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 -176 32 ) ( 177 -176 32 ) ( 176 -176 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 112 -176 80 ) ( 112 -48 64 ) ( 112 -176 64 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 19 +{ +( 96 272 16 ) ( 96 273 16 ) ( 96 272 17 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 96 272 16 ) ( 96 272 17 ) ( 97 272 16 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 96 272 16 ) ( 97 272 16 ) ( 96 273 16 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 224 336 384 ) ( 224 337 384 ) ( 225 336 384 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 224 336 32 ) ( 225 336 32 ) ( 224 336 33 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 224 336 32 ) ( 224 336 33 ) ( 224 337 32 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +} +// brush 20 +{ +( 336 112 16 ) ( 336 113 16 ) ( 336 112 17 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 336 112 16 ) ( 336 112 17 ) ( 337 112 16 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 336 112 16 ) ( 337 112 16 ) ( 336 113 16 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 416 208 112 ) ( 416 209 112 ) ( 417 208 112 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 416 208 32 ) ( 417 208 32 ) ( 416 208 33 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 416 208 32 ) ( 416 208 33 ) ( 416 209 32 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +} +// brush 21 +{ +( 144 160 16 ) ( 144 161 16 ) ( 144 160 17 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 144 160 16 ) ( 144 160 17 ) ( 145 160 16 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 144 160 16 ) ( 145 160 16 ) ( 144 161 16 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 192 272 224 ) ( 192 273 224 ) ( 193 272 224 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 192 272 32 ) ( 193 272 32 ) ( 192 272 33 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 192 272 32 ) ( 192 272 33 ) ( 192 273 32 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +} +// brush 22 +{ +( 320 -224 128 ) ( 320 -223 128 ) ( 320 -224 129 ) mapping_defaults/ProtoGrey 128 0 0 0.25 0.25 +( 320 -224 128 ) ( 320 -224 129 ) ( 321 -224 128 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 320 -224 128 ) ( 321 -224 128 ) ( 320 -223 128 ) mapping_defaults/ProtoGrey 0 -128 0 0.25 0.25 +( 368 -160 144 ) ( 368 -159 144 ) ( 369 -160 144 ) mapping_defaults/ProtoGrey 0 -128 0 0.25 0.25 +( 368 -160 144 ) ( 369 -160 144 ) ( 368 -160 145 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 368 -160 144 ) ( 368 -160 145 ) ( 368 -159 144 ) mapping_defaults/ProtoGrey 128 0 0 0.25 0.25 +} +// brush 23 +{ +( 336 0 304 ) ( 336 1 304 ) ( 336 0 305 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 336 0 304 ) ( 336 0 305 ) ( 337 0 304 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 336 0 304 ) ( 337 0 304 ) ( 336 1 304 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 384 96 320 ) ( 384 97 320 ) ( 385 96 320 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 384 96 320 ) ( 385 96 320 ) ( 384 96 321 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 560 96 320 ) ( 560 96 321 ) ( 560 97 320 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +} +// brush 24 +{ +( 17.071796769724585 1215.7128129211023 96 ) ( 49.07179676972447 1160.2871870788977 96 ) ( 49.07179676972447 1160.2871870788977 16 ) mapping_defaults/ProtoDark -222.7843 -48 0 0.8660254 1 +( 24 1219.7128129211023 16 ) ( 24 1219.7128129211023 96 ) ( 17.071796769724585 1215.7128129211023 96 ) mapping_defaults/ProtoDark -171.7128 -48 0 0.8660254 1 +( 56 1164.2871870788977 16 ) ( 24 1219.7128129211023 16 ) ( 17.071796769724585 1215.7128129211023 16 ) mapping_defaults/ProtoDark -113.64099 255.30194 30 1 1 +( 17.071796769724585 1215.7128129211023 96 ) ( 24 1219.7128129211023 96 ) ( 56 1164.2871870788977 96 ) mapping_defaults/ProtoDark -113.64099 255.30194 30 1 1 +( 49.07179676972447 1160.2871870788977 96 ) ( 56 1164.2871870788977 96 ) ( 56 1164.2871870788977 16 ) mapping_defaults/ProtoDark -171.66324 -48 0 0.8660254 1 +( 56 1164.2871870788977 96 ) ( 24 1219.7128129211023 96 ) ( 24 1219.7128129211023 16 ) mapping_defaults/ProtoDark -222.40308 -48 0 0.8660254 1 +} +// brush 25 +{ +( 1.3725830020305807 1241.3725830020303 96 ) ( 7.029437251522893 1235.7157287525379 96 ) ( 7.029437251522893 1235.7157287525379 16 ) mapping_defaults/ProtoDark 53.565918 -48 180 0.70710677 -1 +( 46.62741699796953 1286.6274169979697 96 ) ( 1.3725830020305807 1241.3725830020303 96 ) ( 1.3725830020305807 1241.3725830020303 16 ) mapping_defaults/ProtoDark -53.565918 -48 0 0.70710677 1 +( 7.029437251522893 1235.7157287525379 16 ) ( 52.28427124746196 1280.9705627484773 16 ) ( 46.62741699796953 1286.6274169979697 16 ) mapping_defaults/ProtoDark 120.81244 189.75354 315 1 1 +( 46.62741699796953 1286.6274169979697 96 ) ( 52.28427124746196 1280.9705627484773 96 ) ( 7.029437251522893 1235.7157287525379 96 ) mapping_defaults/ProtoDark 120.81244 189.75354 315 1 1 +( 52.28427124746196 1280.9705627484773 16 ) ( 52.28427124746196 1280.9705627484773 96 ) ( 46.62741699796953 1286.6274169979697 96 ) mapping_defaults/ProtoDark 53.565918 -48 180 0.70710677 -1 +( 7.029437251522893 1235.7157287525379 96 ) ( 52.28427124746196 1280.9705627484773 96 ) ( 52.28427124746196 1280.9705627484773 16 ) mapping_defaults/ProtoDark -53.565918 -48 0 0.70710677 1 +} +// brush 26 +{ +( 48 1280 16 ) ( 48 1281 16 ) ( 48 1280 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 48 1280 16 ) ( 48 1280 17 ) ( 49 1280 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 48 1280 16 ) ( 49 1280 16 ) ( 48 1281 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 200 1288 120 ) ( 200 1289 120 ) ( 201 1288 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 200 1288 24 ) ( 201 1288 24 ) ( 200 1288 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 200 1288 24 ) ( 200 1288 25 ) ( 200 1289 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 27 +{ +( 48 1264 96 ) ( 48 1265 96 ) ( 48 1264 97 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 48 1144 96 ) ( 48 1144 97 ) ( 49 1144 96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 48 1264 96 ) ( 49 1264 96 ) ( 48 1265 96 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 56 1280 120 ) ( 56 1281 120 ) ( 57 1280 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 56 1280 104 ) ( 57 1280 104 ) ( 56 1280 105 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 56 1280 104 ) ( 56 1280 105 ) ( 56 1281 104 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 28 +{ +( 48 1144 16 ) ( 48 1145 16 ) ( 48 1144 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 48 1144 16 ) ( 48 1144 17 ) ( 49 1144 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 48 1144 16 ) ( 49 1144 16 ) ( 48 1145 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 56 1160 96 ) ( 56 1161 96 ) ( 57 1160 96 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 56 1160 24 ) ( 57 1160 24 ) ( 56 1160 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 56 1160 24 ) ( 56 1160 25 ) ( 56 1161 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 29 +{ +( 48 1112 16 ) ( 48 1113 16 ) ( 48 1112 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 48 1112 16 ) ( 48 1112 17 ) ( 49 1112 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 48 1112 16 ) ( 49 1112 16 ) ( 48 1113 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 64 1144 120 ) ( 64 1145 120 ) ( 65 1144 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 64 1144 24 ) ( 65 1144 24 ) ( 64 1144 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 56 1144 24 ) ( 56 1144 25 ) ( 56 1145 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 30 +{ +( 248 1208 64 ) ( 200 1288 64 ) ( 200 1288 120 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 248 1208 120 ) ( 256 1202.6666666666606 120 ) ( 256 1202.6666666666579 64 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 256 1202.6666666666579 64 ) ( 256 1288 64 ) ( 200 1288 64 ) mapping_defaults/ProtoDark -80 223.99988 0 1 1 +( 200 1288 120 ) ( 256 1288 120 ) ( 256 1202.6666666666606 120 ) mapping_defaults/ProtoDark -80 223.99988 0 1 1 +( 256 1288 64 ) ( 256 1288 120 ) ( 200 1288 120 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 256 1202.6666666666606 120 ) ( 256 1288 120 ) ( 256 1288 64 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 31 +{ +( 200 1200 16 ) ( 200 1201 16 ) ( 200 1200 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 200 1240 96 ) ( 224 1224 224 ) ( 224 1224 96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 200 1200 16 ) ( 201 1200 16 ) ( 200 1201 16 ) mapping_defaults/ProtoDark -80 224.99988 0 1 1 +( 200 1240 64 ) ( 224 1352 64 ) ( 224 1224 64 ) mapping_defaults/ProtoDark -80 224.99988 0 1 1 +( 360 1288 24 ) ( 361 1288 24 ) ( 360 1288 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 256 1288 24 ) ( 256 1288 25 ) ( 256 1289 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 32 +{ +( 256 1200 16 ) ( 256 1201 16 ) ( 256 1200 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 256 1200 16 ) ( 256 1200 17 ) ( 257 1200 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 256 1200 16 ) ( 257 1200 16 ) ( 256 1201 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 264 1296 120 ) ( 264 1297 120 ) ( 265 1296 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 264 1288 24 ) ( 265 1288 24 ) ( 264 1288 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 272 1296 24 ) ( 272 1296 25 ) ( 272 1297 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 33 +{ +( 448 1200 16 ) ( 448 1201 16 ) ( 448 1200 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 440 1200 16 ) ( 440 1200 17 ) ( 441 1200 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 440 1200 16 ) ( 441 1200 16 ) ( 440 1201 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 448 1296 120 ) ( 448 1297 120 ) ( 449 1296 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 448 1288 24 ) ( 449 1288 24 ) ( 448 1288 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 456 1296 24 ) ( 456 1296 25 ) ( 456 1297 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 34 +{ +( 272 1200 112 ) ( 272 1201 112 ) ( 272 1200 113 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 272 1200 112 ) ( 272 1200 113 ) ( 273 1200 112 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 272 1200 112 ) ( 273 1200 112 ) ( 272 1201 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 280 1288 120 ) ( 280 1289 120 ) ( 281 1288 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 280 1288 120 ) ( 281 1288 120 ) ( 280 1288 121 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 448 1288 120 ) ( 448 1288 121 ) ( 448 1289 120 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 35 +{ +( 272 1200 96 ) ( 272 1201 96 ) ( 272 1200 97 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 272 1200 96 ) ( 272 1200 97 ) ( 273 1200 96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 272 1200 96 ) ( 273 1200 96 ) ( 272 1201 96 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 312 1208 112 ) ( 312 1209 112 ) ( 313 1208 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 312 1208 104 ) ( 313 1208 104 ) ( 312 1208 105 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 448 1208 104 ) ( 448 1208 105 ) ( 448 1209 104 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 36 +{ +( 264 1288 16 ) ( 264 1289 16 ) ( 264 1288 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 264 1288 16 ) ( 264 1288 17 ) ( 265 1288 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 264 1288 16 ) ( 265 1288 16 ) ( 264 1289 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 272 1344 120 ) ( 272 1345 120 ) ( 273 1344 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 272 1344 24 ) ( 273 1344 24 ) ( 272 1344 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 272 1344 24 ) ( 272 1344 25 ) ( 272 1345 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 37 +{ +( 272 1288 112 ) ( 272 1289 112 ) ( 272 1288 113 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 272 1288 112 ) ( 272 1288 113 ) ( 273 1288 112 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 272 1288 112 ) ( 273 1288 112 ) ( 272 1289 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 280 1344 120 ) ( 280 1345 120 ) ( 281 1344 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 280 1344 120 ) ( 281 1344 120 ) ( 280 1344 121 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 456 1344 120 ) ( 456 1344 121 ) ( 456 1345 120 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 38 +{ +( 272 1336 16 ) ( 272 1337 16 ) ( 272 1336 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 272 1336 16 ) ( 272 1336 17 ) ( 273 1336 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 272 1336 16 ) ( 273 1336 16 ) ( 272 1337 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 392 1344 112 ) ( 392 1345 112 ) ( 393 1344 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 392 1344 24 ) ( 393 1344 24 ) ( 392 1344 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 456 1344 24 ) ( 456 1344 25 ) ( 456 1345 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 39 +{ +( 56 1112 16 ) ( 56 1113 16 ) ( 56 1112 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 56 1112 16 ) ( 56 1112 17 ) ( 57 1112 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 56 1112 16 ) ( 57 1112 16 ) ( 56 1113 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 504 1120 120 ) ( 504 1121 120 ) ( 505 1120 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 504 1120 24 ) ( 505 1120 24 ) ( 504 1120 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 176 1112 80 ) ( 176 1112 88 ) ( 176 1240 88 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 40 +{ +( 176 1112 120 ) ( 176 1240 128 ) ( 176 1112 128 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 56 1112 56 ) ( 56 1112 57 ) ( 57 1112 56 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 56 1112 88 ) ( 57 1112 88 ) ( 56 1113 88 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 504 1120 128 ) ( 504 1121 128 ) ( 505 1120 128 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 504 1120 64 ) ( 505 1120 64 ) ( 504 1120 65 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 240 1112 104 ) ( 240 1112 112 ) ( 240 1240 112 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 41 +{ +( 240 1112 64 ) ( 240 1240 72 ) ( 240 1112 72 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 56 1112 16 ) ( 56 1112 17 ) ( 57 1112 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 56 1112 16 ) ( 57 1112 16 ) ( 56 1113 16 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 504 1120 128 ) ( 504 1121 128 ) ( 505 1120 128 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 504 1120 24 ) ( 505 1120 24 ) ( 504 1120 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 504 1120 24 ) ( 504 1120 25 ) ( 504 1121 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 42 +{ +( 496 904 16 ) ( 496 905 16 ) ( 496 904 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 496 896 16 ) ( 496 896 17 ) ( 497 896 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 496 904 16 ) ( 497 904 16 ) ( 496 905 16 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 504 1112 272 ) ( 504 1113 272 ) ( 505 1112 272 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 504 1120 24 ) ( 505 1120 24 ) ( 504 1120 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 504 1112 24 ) ( 504 1112 25 ) ( 504 1113 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 43 +{ +( 240 1120 120 ) ( 240 1121 120 ) ( 240 1120 121 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 240 1120 120 ) ( 240 1120 121 ) ( 241 1120 120 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 240 1120 120 ) ( 241 1120 120 ) ( 240 1121 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 456 1288 128 ) ( 456 1289 128 ) ( 457 1288 128 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 456 1288 128 ) ( 457 1288 128 ) ( 456 1288 129 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 456 1288 128 ) ( 456 1288 129 ) ( 456 1289 128 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 44 +{ +( 176 1008 224 ) ( 176 1009 224 ) ( 176 1008 225 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +( 184 1008 224 ) ( 184 1008 225 ) ( 185 1008 224 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 184 1008 224 ) ( 185 1008 224 ) ( 184 1009 224 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 496 1088 272 ) ( 496 1089 272 ) ( 497 1088 272 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 496 1116 232 ) ( 497 1116 232 ) ( 496 1116 233 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 496 1088 232 ) ( 496 1088 233 ) ( 496 1089 232 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +} +// brush 45 +{ +( 168 1056 16 ) ( 168 1057 16 ) ( 168 1056 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 168 696 16 ) ( 168 696 17 ) ( 169 696 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 912 248 ) ( 304 936 248 ) ( 176 936 248 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 1112 272 ) ( 176 1113 272 ) ( 177 1112 272 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 1116 24 ) ( 177 1116 24 ) ( 176 1116 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 1112 24 ) ( 176 1112 25 ) ( 176 1113 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 46 +{ +( 168 1056 16 ) ( 168 1057 16 ) ( 168 1056 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 176 952 216 ) ( 176 952 232 ) ( 304 952 232 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 912 208 ) ( 304 936 208 ) ( 176 936 208 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 912 248 ) ( 176 936 248 ) ( 304 936 248 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 1116 24 ) ( 177 1116 24 ) ( 176 1116 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 1112 24 ) ( 176 1112 25 ) ( 176 1113 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 47 +{ +( 168 1056 16 ) ( 168 1057 16 ) ( 168 1056 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 176 872 216 ) ( 176 872 224 ) ( 304 872 224 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 912 208 ) ( 304 936 208 ) ( 176 936 208 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 912 248 ) ( 176 936 248 ) ( 304 936 248 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 912 216 ) ( 304 912 224 ) ( 176 912 224 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 1112 24 ) ( 176 1112 25 ) ( 176 1113 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 48 +{ +( 168 1056 16 ) ( 168 1057 16 ) ( 168 1056 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 176 784 216 ) ( 176 784 224 ) ( 304 784 224 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 912 208 ) ( 304 936 208 ) ( 176 936 208 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 912 248 ) ( 176 936 248 ) ( 304 936 248 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 832 216 ) ( 304 832 232 ) ( 176 832 232 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 1112 24 ) ( 176 1112 25 ) ( 176 1113 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 49 +{ +( 168 1056 16 ) ( 168 1057 16 ) ( 168 1056 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 168 696 16 ) ( 168 696 17 ) ( 169 696 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 912 208 ) ( 304 936 208 ) ( 176 936 208 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 912 248 ) ( 176 936 248 ) ( 304 936 248 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 744 224 ) ( 304 744 232 ) ( 176 744 232 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 1112 24 ) ( 176 1112 25 ) ( 176 1113 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 50 +{ +( 176 912 264 ) ( 176 913 264 ) ( 176 912 265 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 176 656 264 ) ( 176 656 265 ) ( 177 656 264 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 176 912 264 ) ( 177 912 264 ) ( 176 913 264 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 496 1008 272 ) ( 496 1009 272 ) ( 497 1008 272 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 496 1008 272 ) ( 497 1008 272 ) ( 496 1008 273 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 368 1008 272 ) ( 368 1008 273 ) ( 368 1009 272 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 51 +{ +( 168 1056 16 ) ( 168 1057 16 ) ( 168 1056 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 168 696 16 ) ( 168 696 17 ) ( 169 696 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 720 112 ) ( 304 784 112 ) ( 176 784 112 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 912 208 ) ( 176 936 208 ) ( 304 936 208 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 1116 24 ) ( 177 1116 24 ) ( 176 1116 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 1112 24 ) ( 176 1112 25 ) ( 176 1113 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 52 +{ +( 168 1056 16 ) ( 168 1057 16 ) ( 168 1056 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 168 696 16 ) ( 168 696 17 ) ( 169 696 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 168 1056 16 ) ( 169 1056 16 ) ( 168 1057 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 176 720 112 ) ( 176 784 112 ) ( 304 784 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 176 728 32 ) ( 304 728 40 ) ( 176 728 40 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 176 1112 24 ) ( 176 1112 25 ) ( 176 1113 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 53 +{ +( 168 1056 16 ) ( 168 1057 16 ) ( 168 1056 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 176 816 40 ) ( 176 816 56 ) ( 304 816 56 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 168 1056 16 ) ( 169 1056 16 ) ( 168 1057 16 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 720 112 ) ( 176 784 112 ) ( 304 784 112 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 1112 24 ) ( 177 1112 24 ) ( 176 1112 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 1112 24 ) ( 176 1112 25 ) ( 176 1113 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 54 +{ +( 168 656 16 ) ( 168 657 16 ) ( 168 656 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 168 656 16 ) ( 168 656 17 ) ( 169 656 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 168 656 16 ) ( 169 656 16 ) ( 168 657 16 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 696 272 ) ( 176 697 272 ) ( 177 696 272 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 696 24 ) ( 177 696 24 ) ( 176 696 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 696 24 ) ( 176 696 25 ) ( 176 697 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 55 +{ +( 496 656 264 ) ( 496 657 264 ) ( 496 656 265 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 496 656 264 ) ( 496 656 265 ) ( 497 656 264 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 496 656 184 ) ( 497 656 184 ) ( 496 657 184 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 504 896 272 ) ( 504 897 272 ) ( 505 896 272 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 504 896 272 ) ( 505 896 272 ) ( 504 896 273 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 504 896 272 ) ( 504 896 273 ) ( 504 897 272 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 56 +{ +( 168 640 16 ) ( 168 641 16 ) ( 168 640 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 168 648 16 ) ( 168 648 17 ) ( 169 648 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 168 640 16 ) ( 169 640 16 ) ( 168 641 16 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 536 656 272 ) ( 536 657 272 ) ( 537 656 272 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 536 656 24 ) ( 537 656 24 ) ( 536 656 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 536 656 24 ) ( 536 656 25 ) ( 536 657 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 57 +{ +( 496 656 176 ) ( 496 657 176 ) ( 496 656 177 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 496 656 176 ) ( 496 656 177 ) ( 497 656 176 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 496 656 16 ) ( 497 656 16 ) ( 496 657 16 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 504 664 184 ) ( 504 665 184 ) ( 505 664 184 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 504 728 184 ) ( 505 728 184 ) ( 504 728 185 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 504 664 184 ) ( 504 664 185 ) ( 504 665 184 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 58 +{ +( 176 688 128 ) ( 176 689 128 ) ( 176 688 129 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 176 656 128 ) ( 176 656 129 ) ( 177 656 128 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 176 688 128 ) ( 177 688 128 ) ( 176 689 128 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 240 872 136 ) ( 240 873 136 ) ( 241 872 136 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 240 944 136 ) ( 241 944 136 ) ( 240 944 137 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 264 872 136 ) ( 264 872 137 ) ( 264 873 136 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 59 +{ +( 260 860 136 ) ( 260 861 136 ) ( 260 860 137.85714285714275 ) mapping_defaults/ProtoDark -224 -110.769226 0 1 1.8571428 +( 260 704 136 ) ( 260 704 137.85714285714275 ) ( 261.8571428571426 704 136 ) mapping_defaults/ProtoDark 40 -110.769226 0 1.8571428 1.8571428 +( 260 860 136 ) ( 261.8571428571426 860 136 ) ( 260 861 136 ) mapping_defaults/ProtoDark 40 224 0 1.8571428 1 +( 267.42857142857144 992 188 ) ( 267.42857142857144 993 188 ) ( 269.2857142857146 992 188 ) mapping_defaults/ProtoDark 40 224 0 1.8571428 1 +( 267.42857142857144 944 143.42857142857122 ) ( 269.2857142857146 944 143.42857142857122 ) ( 267.42857142857144 944 145.28571428571453 ) mapping_defaults/ProtoDark 40 -110.769226 0 1.8571428 1.8571428 +( 267.42857142857144 992 143.42857142857122 ) ( 267.42857142857144 992 145.28571428571453 ) ( 267.42857142857144 993 143.42857142857122 ) mapping_defaults/ProtoDark -224 -110.769226 0 1 1.8571428 +} +// brush 60 +{ +( 240 1040 192 ) ( 240 1048 184 ) ( 240 1048 312 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +( 200 1028 204 ) ( 204 1028 332 ) ( 204 1028 204 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 168 1088 144 ) ( 168 1080 152 ) ( 296 1080 152 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 296 1120 224 ) ( 296 1121 224 ) ( 297 1120 224 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 192 1060 172 ) ( 212 1060 172 ) ( 212 1060 300 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 496 1120 136 ) ( 496 1120 137 ) ( 496 1121 136 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +} +// brush 61 +{ +( 176 960 128 ) ( 176 961 128 ) ( 176 960 129 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +( 192 1060 172 ) ( 212 1060 300 ) ( 212 1060 172 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 168 1088 144 ) ( 168 1080 152 ) ( 296 1080 152 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 176 960 128 ) ( 177 960 128 ) ( 176 961 128 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 296 1120 176 ) ( 296 1121 176 ) ( 297 1120 176 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 296 1120 136 ) ( 297 1120 136 ) ( 296 1120 137 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 236 1060 172 ) ( 236 1060 176 ) ( 236 1188 176 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +} +// brush 62 +{ +( 240 1024 208 ) ( 240 1020 340 ) ( 240 1020 212 ) mapping_defaults/ProtoBrightBlue -223.99994 -48.000015 0 1 1 +( 168 1088 144 ) ( 168 1080 152 ) ( 296 1080 152 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 296 1120 224 ) ( 296 1121 224 ) ( 297 1120 224 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 200 1028 204 ) ( 204 1028 204 ) ( 204 1028 332 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 496 1120 136 ) ( 496 1120 137 ) ( 496 1121 136 ) mapping_defaults/ProtoBrightBlue -223.99994 -48.000015 0 1 1 +} +// brush 63 +{ +( 176 960 128 ) ( 176 961 128 ) ( 176 960 129 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +( 168 1088 144 ) ( 168 1080 152 ) ( 296 1080 152 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 296 1120 224 ) ( 296 1121 224 ) ( 297 1120 224 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 176 1020 212 ) ( 184 1020 212 ) ( 184 1020 340 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 240 1024 208 ) ( 240 1020 212 ) ( 240 1020 340 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +} +// brush 64 +{ +( 236 1060 172 ) ( 236 1188 176 ) ( 236 1060 176 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +( 192 1060 172 ) ( 212 1060 300 ) ( 212 1060 172 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 168 1088 144 ) ( 168 1080 152 ) ( 296 1080 152 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 176 960 128 ) ( 177 960 128 ) ( 176 961 128 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 240 1120 176 ) ( 248 1248 176 ) ( 248 1120 176 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 296 1120 136 ) ( 297 1120 136 ) ( 296 1120 137 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 496 1120 136 ) ( 496 1120 137 ) ( 496 1121 136 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +} +// brush 65 +{ +( 304 656 16 ) ( 292 656 8 ) ( 292 784 8 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 88 656 20 ) ( 88 656 21 ) ( 89 656 20 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 88 688 -169.33333333333326 ) ( 89 688 -169.33333333333326 ) ( 88 689 -169.33333333333326 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 208 704 24 ) ( 209 704 24 ) ( 208 704 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 160 656 -92 ) ( 172 656 -84 ) ( 172 784 -84 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 304 704 24 ) ( 304 704 25 ) ( 304 705 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 66 +{ +( -108 656 -172 ) ( -108 657 -172 ) ( -108 656 -171 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 108 656 -172 ) ( 108 656 -171 ) ( 109 656 -172 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 108 656 -172 ) ( 109 656 -172 ) ( 108 657 -172 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 120 700 -168 ) ( 120 701 -168 ) ( 121 700 -168 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 120 984 -168 ) ( 121 984 -168 ) ( 120 984 -167 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 320 700 -168 ) ( 320 700 -167 ) ( 320 701 -168 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 67 +{ +( -112 984 -96 ) ( -112 985 -96 ) ( -112 984 -95 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( -96 984 -96 ) ( -96 984 -95 ) ( -95 984 -96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( -96 984 -172 ) ( -95 984 -172 ) ( -96 985 -172 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( -20 988 4 ) ( -20 989 4 ) ( -19 988 4 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( -20 988 -92 ) ( -19 988 -92 ) ( -20 988 -91 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 320 988 -92 ) ( 320 988 -91 ) ( 320 989 -92 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 68 +{ +( 316 956 -96 ) ( 316 957 -96 ) ( 316 956 -95 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 316 640 -96 ) ( 316 640 -95 ) ( 317 640 -96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 316 956 -172 ) ( 317 956 -172 ) ( 316 957 -172 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 320 972 4 ) ( 320 973 4 ) ( 321 972 4 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 320 992 -92 ) ( 321 992 -92 ) ( 320 992 -91 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 320 972 -92 ) ( 320 972 -91 ) ( 320 973 -92 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 69 +{ +( -112 980 -96 ) ( -112 981 -96 ) ( -112 980 -95 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( -112 656 -96 ) ( -112 656 -95 ) ( -111 656 -96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( -112 980 -172 ) ( -111 980 -172 ) ( -112 981 -172 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( -108 984 4 ) ( -108 985 4 ) ( -107 984 4 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( -108 984 -92 ) ( -107 984 -92 ) ( -108 984 -91 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( -108 984 -92 ) ( -108 984 -91 ) ( -108 985 -92 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 70 +{ +( -168 700 4 ) ( -168 701 4 ) ( -168 700 5 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 160 656 4 ) ( 160 656 5 ) ( 161 656 4 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 160 700 4 ) ( 161 700 4 ) ( 160 701 4 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 176 704 8 ) ( 176 705 8 ) ( 177 704 8 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 176 704 8 ) ( 177 704 8 ) ( 176 704 9 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 124 704 8 ) ( 124 704 9 ) ( 124 705 8 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 71 +{ +( -112 652 -96 ) ( -112 653 -96 ) ( -112 652 -95 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( -112 652 -96 ) ( -112 652 -95 ) ( -111 652 -96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( -112 652 -172 ) ( -111 652 -172 ) ( -112 653 -172 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 176 656 4 ) ( 176 657 4 ) ( 177 656 4 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 176 656 -92 ) ( 177 656 -92 ) ( 176 656 -91 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 320 656 -92 ) ( 320 656 -91 ) ( 320 657 -92 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 72 +{ +( 264 656 16 ) ( 264 657 16 ) ( 264 656 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 276 704 120 ) ( 288 704 112 ) ( 288 832 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 360 656 16 ) ( 360 656 17 ) ( 361 656 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 360 656 16 ) ( 361 656 16 ) ( 360 657 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 488 704 20 ) ( 489 704 20 ) ( 488 704 21 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 264 676 136 ) ( 276 804 128 ) ( 276 676 128 ) mapping_defaults/ProtoDark -80 224 0 1 1 +} +// brush 73 +{ +( 272 1200 16 ) ( 272 1201 16 ) ( 272 1200 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 272 1200 16 ) ( 272 1200 17 ) ( 273 1200 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 272 1200 16 ) ( 273 1200 16 ) ( 272 1201 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 444 1232 44 ) ( 428 1232 44 ) ( 428 1360 44 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 280 1216 24 ) ( 281 1216 24 ) ( 280 1216 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 448 1232 24 ) ( 448 1232 25 ) ( 448 1233 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 74 +{ +( 272 1200 16 ) ( 272 1201 16 ) ( 272 1200 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 272 1200 16 ) ( 272 1200 17 ) ( 273 1200 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 444 1232 44 ) ( 428 1360 44 ) ( 428 1232 44 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 280 1232 56 ) ( 280 1233 56 ) ( 281 1232 56 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 280 1232 24 ) ( 281 1232 24 ) ( 280 1232 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 448 1232 24 ) ( 448 1232 25 ) ( 448 1233 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 75 +{ +( 272 1216 28 ) ( 272 1217 28 ) ( 272 1216 29 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 272 1216 28 ) ( 272 1216 29 ) ( 273 1216 28 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 272 1216 28 ) ( 273 1216 28 ) ( 272 1217 28 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 448 1236 32 ) ( 448 1237 32 ) ( 449 1236 32 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 448 1232 32 ) ( 449 1232 32 ) ( 448 1232 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 448 1236 32 ) ( 448 1236 33 ) ( 448 1237 32 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 76 +{ +( 236 1172 120 ) ( 236 1173 120 ) ( 236 1172 121 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 228 1120 120 ) ( 228 1120 121 ) ( 229 1120 120 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 228 1172 120 ) ( 229 1172 120 ) ( 228 1173 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 240 1284 272 ) ( 240 1285 272 ) ( 241 1284 272 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 240 1288 124 ) ( 241 1288 124 ) ( 240 1288 125 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 240 1284 124 ) ( 240 1284 125 ) ( 240 1285 124 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 77 +{ +( 240 1284 128 ) ( 240 1285 128 ) ( 240 1284 129 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 240 1284 128 ) ( 240 1284 129 ) ( 241 1284 128 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 240 1284 128 ) ( 241 1284 128 ) ( 240 1285 128 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 452 1288 216 ) ( 452 1289 216 ) ( 453 1288 216 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 452 1288 132 ) ( 453 1288 132 ) ( 452 1288 133 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 456 1288 132 ) ( 456 1288 133 ) ( 456 1289 132 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 78 +{ +( 168 1120 176 ) ( 168 1121 176 ) ( 168 1120 177 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 244 1116 176 ) ( 244 1116 177 ) ( 245 1116 176 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 244 1120 176 ) ( 245 1120 176 ) ( 244 1121 176 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 348 1124 272 ) ( 348 1125 272 ) ( 349 1124 272 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 348 1124 180 ) ( 349 1124 180 ) ( 348 1124 181 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 496 1124 180 ) ( 496 1124 181 ) ( 496 1125 180 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 79 +{ +( 688 912 16 ) ( 688 913 16 ) ( 688 912 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 688 912 16 ) ( 688 912 17 ) ( 689 912 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 688 912 16 ) ( 689 912 16 ) ( 688 913 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 704 1136 272 ) ( 704 1137 272 ) ( 705 1136 272 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 704 1136 32 ) ( 705 1136 32 ) ( 704 1136 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 704 1136 32 ) ( 704 1136 33 ) ( 704 1137 32 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 80 +{ +( 592 1216 16 ) ( 592 1217 16 ) ( 592 1216 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 592 1216 16 ) ( 592 1216 17 ) ( 593 1216 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 592 1216 16 ) ( 593 1216 16 ) ( 592 1217 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 800 1232 288 ) ( 800 1233 288 ) ( 801 1232 288 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 800 1232 32 ) ( 801 1232 32 ) ( 800 1232 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 800 1232 32 ) ( 800 1232 33 ) ( 800 1233 32 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 81 +{ +( 1024 896 176 ) ( 1008 896 160 ) ( 1008 1024 160 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 832 896 16 ) ( 832 896 17 ) ( 833 896 16 ) mapping_defaults/ProtoDark -80 -47.999992 0 1 1 +( 832 896 16 ) ( 833 896 16 ) ( 832 897 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1040 976 32 ) ( 1041 976 32 ) ( 1040 976 33 ) mapping_defaults/ProtoDark -80 -47.999992 0 1 1 +( 1072 944 32 ) ( 1072 944 33 ) ( 1072 945 32 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 82 +{ +( 1072 896 48 ) ( 1072 897 48 ) ( 1072 896 49 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 1040 896 48 ) ( 1040 896 49 ) ( 1041 896 48 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1056 896 176 ) ( 1088 896 176 ) ( 1088 1024 176 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 976 224 ) ( 1136 977 224 ) ( 1137 976 224 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 976 64 ) ( 1137 976 64 ) ( 1136 976 65 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1136 976 64 ) ( 1136 976 65 ) ( 1136 977 64 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 83 +{ +( 1056 976 112 ) ( 1056 976 96 ) ( 1056 1104 96 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 864 976 16 ) ( 864 976 17 ) ( 865 976 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1056 976 112 ) ( 1088 976 112 ) ( 1088 1104 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 1056 496 ) ( 1136 1057 496 ) ( 1137 1056 496 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 1056 32 ) ( 1137 1056 32 ) ( 1136 1056 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1136 1056 32 ) ( 1136 1056 33 ) ( 1136 1057 32 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 84 +{ +( 864 976 16 ) ( 864 977 16 ) ( 864 976 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 864 976 16 ) ( 864 976 17 ) ( 865 976 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 864 976 16 ) ( 865 976 16 ) ( 864 977 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1056 976 112 ) ( 1040 976 112 ) ( 1040 1104 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 1056 32 ) ( 1137 1056 32 ) ( 1136 1056 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 960 976 112 ) ( 960 1104 96 ) ( 960 976 96 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 85 +{ +( 864 976 16 ) ( 864 977 16 ) ( 864 976 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 864 976 16 ) ( 864 976 17 ) ( 865 976 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1056 976 112 ) ( 1040 1104 112 ) ( 1040 976 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 1056 496 ) ( 1136 1057 496 ) ( 1137 1056 496 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 1056 32 ) ( 1137 1056 32 ) ( 1136 1056 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1056 976 112 ) ( 1056 1104 96 ) ( 1056 976 96 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 86 +{ +( 1136 896 208 ) ( 1136 897 208 ) ( 1136 896 209 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 1136 896 208 ) ( 1136 896 209 ) ( 1137 896 208 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1136 896 208 ) ( 1137 896 208 ) ( 1136 897 208 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1152 928 224 ) ( 1152 929 224 ) ( 1153 928 224 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1152 1136 224 ) ( 1153 1136 224 ) ( 1152 1136 225 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1200 928 224 ) ( 1200 928 225 ) ( 1200 929 224 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 87 +{ +( 880 1056 208 ) ( 880 1057 208 ) ( 880 1056 209 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 1120 1056 208 ) ( 1120 1056 209 ) ( 1121 1056 208 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1120 1056 208 ) ( 1121 1056 208 ) ( 1120 1057 208 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 1136 224 ) ( 1137 1136 224 ) ( 1136 1136 225 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1136 1136 224 ) ( 1072 1136 240 ) ( 1072 1264 240 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 1120 224 ) ( 1136 1120 225 ) ( 1136 1121 224 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 88 +{ +( 784 1056 208 ) ( 784 1057 208 ) ( 784 1056 209 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 784 1056 208 ) ( 784 1056 209 ) ( 785 1056 208 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 784 1056 208 ) ( 785 1056 208 ) ( 784 1057 208 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 864 1136 288 ) ( 864 1137 288 ) ( 865 1136 288 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 864 1136 224 ) ( 865 1136 224 ) ( 864 1136 225 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 880 1136 224 ) ( 880 1136 225 ) ( 880 1137 224 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +} +// entity 1 +{ +"classname" "enemy_spawn" +"origin" "-64 -48 40" +} +// entity 2 +{ +"classname" "info_player_start" +"origin" "-96 128 40" +} +// entity 3 +{ +"classname" "enemy_spawn" +"origin" "120 1216 40" +} diff --git a/projects/content/bsp/testmap.map b/projects/content/bsp/testmap.map new file mode 100644 index 0000000..f73e59c --- /dev/null +++ b/projects/content/bsp/testmap.map @@ -0,0 +1,857 @@ +// Game: Deathwish +// Format: Standard +// entity 0 +{ +"classname" "worldspawn" +// brush 0 +{ +( -288 -144 -16 ) ( -288 -143 -16 ) ( -288 -144 -15 ) mapping_defaults/ProtoDark 64 0 0 0.25 0.25 +( -128 -240 -16 ) ( -128 -240 -15 ) ( -127 -240 -16 ) mapping_defaults/ProtoDark 0 0 0 0.25 0.25 +( -128 -144 -16 ) ( -127 -144 -16 ) ( -128 -143 -16 ) mapping_defaults/ProtoDark 0 -64 0 0.25 0.25 +( 0 -16 16 ) ( 0 -15 16 ) ( 1 -16 16 ) mapping_defaults/ProtoDark 0 -64 0 0.25 0.25 +( 0 1456 16 ) ( 1 1456 16 ) ( 0 1456 17 ) mapping_defaults/ProtoDark 0 0 0 0.25 0.25 +( 1328 -16 16 ) ( 1328 -16 17 ) ( 1328 -15 16 ) mapping_defaults/ProtoDark 64 0 0 0.25 0.25 +} +// brush 1 +{ +( 80 -80 16 ) ( 80 -79 16 ) ( 80 -80 17 ) mapping_defaults/ProtoOrange 64 0 0 0.25 0.25 +( 80 -80 16 ) ( 80 -80 17 ) ( 81 -80 16 ) mapping_defaults/ProtoOrange 0 0 0 0.25 0.25 +( 80 -80 16 ) ( 81 -80 16 ) ( 80 -79 16 ) mapping_defaults/ProtoOrange 0 -64 0 0.25 0.25 +( 176 -64 96 ) ( 176 -63 96 ) ( 177 -64 96 ) mapping_defaults/ProtoOrange 0 -64 0 0.25 0.25 +( 176 -64 32 ) ( 177 -64 32 ) ( 176 -64 33 ) mapping_defaults/ProtoOrange 0 0 0 0.25 0.25 +( 176 -64 32 ) ( 176 -64 33 ) ( 176 -63 32 ) mapping_defaults/ProtoOrange 64 0 0 0.25 0.25 +} +// brush 2 +{ +( 80 -32 16 ) ( 80 -31 16 ) ( 80 -32 17 ) mapping_defaults/ProtoDarkBlue 80 0 0 1 1 +( 80 -32 16 ) ( 80 -32 17 ) ( 81 -32 16 ) mapping_defaults/ProtoDarkBlue 64 0 0 1 1 +( 80 -32 16 ) ( 81 -32 16 ) ( 80 -31 16 ) mapping_defaults/ProtoDarkBlue 64 -80 0 1 1 +( 96 80 80 ) ( 96 81 80 ) ( 97 80 80 ) mapping_defaults/ProtoDarkBlue 64 -80 0 1 1 +( 96 80 32 ) ( 97 80 32 ) ( 96 80 33 ) mapping_defaults/ProtoDarkBlue 64 0 0 1 1 +( 96 80 32 ) ( 96 80 33 ) ( 96 81 32 ) mapping_defaults/ProtoDarkBlue 80 0 0 1 1 +} +// brush 3 +{ +( -160 -128 16 ) ( -160 -127 16 ) ( -160 -128 17 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +( -160 -128 16 ) ( -160 -128 17 ) ( -159 -128 16 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -160 -128 16 ) ( -159 -128 16 ) ( -160 -127 16 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -128 0 96 ) ( -128 1 96 ) ( -127 0 96 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -128 0 32 ) ( -127 0 32 ) ( -128 0 33 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -128 0 32 ) ( -128 0 33 ) ( -128 1 32 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +} +// brush 4 +{ +( -224 48 16 ) ( -224 49 16 ) ( -224 48 17 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +( -224 48 16 ) ( -224 48 17 ) ( -223 48 16 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -224 48 16 ) ( -223 48 16 ) ( -224 49 16 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -160 128 112 ) ( -160 129 112 ) ( -159 128 112 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -160 128 32 ) ( -159 128 32 ) ( -160 128 33 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -160 128 32 ) ( -160 128 33 ) ( -160 129 32 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +} +// brush 5 +{ +( -112 224 16 ) ( -112 225 16 ) ( -112 224 17 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +( -112 224 16 ) ( -112 224 17 ) ( -111 224 16 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -112 224 16 ) ( -111 224 16 ) ( -112 225 16 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -64 304 192 ) ( -64 305 192 ) ( -63 304 192 ) mapping_defaults/ProtoMaroon 0 -64 0 0.25 0.25 +( -64 304 32 ) ( -63 304 32 ) ( -64 304 33 ) mapping_defaults/ProtoMaroon 0 0 0 0.25 0.25 +( -64 304 32 ) ( -64 304 33 ) ( -64 305 32 ) mapping_defaults/ProtoMaroon 64 0 0 0.25 0.25 +} +// brush 6 +{ +( 208 -192 16 ) ( 208 -191 16 ) ( 208 -192 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 208 -192 16 ) ( 208 -192 17 ) ( 209 -192 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 208 -192 16 ) ( 209 -192 16 ) ( 208 -191 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -128 144 ) ( 288 -127 144 ) ( 289 -128 144 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -128 32 ) ( 289 -128 32 ) ( 288 -128 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -128 32 ) ( 288 -128 33 ) ( 288 -127 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 7 +{ +( 416 -112 16 ) ( 416 -111 16 ) ( 416 -112 17 ) mapping_defaults/ProtoDarkGreen 128 0 0 0.25 0.25 +( 416 -112 16 ) ( 416 -112 17 ) ( 417 -112 16 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 416 -112 16 ) ( 417 -112 16 ) ( 416 -111 16 ) mapping_defaults/ProtoDarkGreen -64 -128 0 0.25 0.25 +( 560 0 144 ) ( 560 1 144 ) ( 561 0 144 ) mapping_defaults/ProtoDarkGreen -64 -128 0 0.25 0.25 +( 560 0 32 ) ( 561 0 32 ) ( 560 0 33 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 560 0 32 ) ( 560 0 33 ) ( 560 1 32 ) mapping_defaults/ProtoDarkGreen 128 0 0 0.25 0.25 +} +// brush 8 +{ +( 352 224 16 ) ( 352 225 16 ) ( 352 224 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 352 224 16 ) ( 352 224 17 ) ( 353 224 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 352 224 16 ) ( 353 224 16 ) ( 352 225 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 512 288 208 ) ( 512 289 208 ) ( 513 288 208 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 512 288 32 ) ( 513 288 32 ) ( 512 288 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 512 288 32 ) ( 512 288 33 ) ( 512 289 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 9 +{ +( -272 -288 16 ) ( -272 -287 16 ) ( -272 -288 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -272 -288 16 ) ( -272 -288 17 ) ( -271 -288 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -272 -288 16 ) ( -271 -288 16 ) ( -272 -287 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -176 -80 32 ) ( -176 -79 32 ) ( -175 -80 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -176 -80 32 ) ( -175 -80 32 ) ( -176 -80 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( -176 -80 32 ) ( -176 -80 33 ) ( -176 -79 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 10 +{ +( 304 16 96 ) ( 304 17 96 ) ( 304 16 97 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 304 16 96 ) ( 304 16 97 ) ( 305 16 96 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 304 16 96 ) ( 305 16 96 ) ( 304 17 96 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 320 48 112 ) ( 320 49 112 ) ( 321 48 112 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 320 48 112 ) ( 321 48 112 ) ( 320 48 113 ) mapping_defaults/ProtoDarkGreen -64 0 0 0.25 0.25 +( 320 48 112 ) ( 320 48 113 ) ( 320 49 112 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 11 +{ +( 256 -48 128 ) ( 256 -47 128 ) ( 256 -48 129 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -48 128 ) ( 288 -48 129 ) ( 289 -48 128 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 288 -48 128 ) ( 289 -48 128 ) ( 288 -47 128 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 304 0 144 ) ( 304 1 144 ) ( 305 0 144 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 304 64 144 ) ( 305 64 144 ) ( 304 64 145 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 304 0 144 ) ( 304 0 145 ) ( 304 1 144 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 12 +{ +( 288 -32 16 ) ( 288 -31 16 ) ( 288 -32 17 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 -32 16 ) ( 288 -32 17 ) ( 289 -32 16 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 16 96 ) ( 288 0 112 ) ( 416 0 112 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 336 112 416 ) ( 336 113 416 ) ( 337 112 416 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 80 128 ) ( 288 32 96 ) ( 416 32 96 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 336 112 32 ) ( 337 112 32 ) ( 336 112 33 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 336 112 32 ) ( 336 112 33 ) ( 336 113 32 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +} +// brush 13 +{ +( 272 -32 16 ) ( 272 -31 16 ) ( 272 -32 17 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 -32 16 ) ( 288 -32 17 ) ( 289 -32 16 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 80 128 ) ( 288 32 96 ) ( 416 32 96 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 288 16 96 ) ( 416 0 112 ) ( 288 0 112 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +( 336 112 32 ) ( 336 112 33 ) ( 336 113 32 ) mapping_defaults/ProtoGreen 0 0 0 0.25 0.25 +} +// brush 14 +{ +( 160 32 16 ) ( 160 33 16 ) ( 160 32 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 160 32 16 ) ( 160 32 17 ) ( 161 32 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 160 32 16 ) ( 161 32 16 ) ( 160 33 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 128 112 ) ( 176 129 112 ) ( 177 128 112 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 128 32 ) ( 177 128 32 ) ( 176 128 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 128 32 ) ( 176 128 33 ) ( 176 129 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 15 +{ +( 256 16 16 ) ( 256 17 16 ) ( 256 16 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 256 16 16 ) ( 256 16 17 ) ( 257 16 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 256 16 16 ) ( 257 16 16 ) ( 256 17 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 272 128 112 ) ( 272 129 112 ) ( 273 128 112 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 272 128 32 ) ( 273 128 32 ) ( 272 128 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 272 128 32 ) ( 272 128 33 ) ( 272 129 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 16 +{ +( 112 -176 80 ) ( 112 -176 64 ) ( 112 -48 64 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 96 -208 16 ) ( 96 -208 17 ) ( 97 -208 16 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 96 -208 16 ) ( 97 -208 16 ) ( 96 -207 16 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 176 -176 64 ) ( 176 -175 64 ) ( 177 -176 64 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 176 -176 32 ) ( 177 -176 32 ) ( 176 -176 33 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 144 -176 48 ) ( 144 -176 80 ) ( 144 -48 80 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +} +// brush 17 +{ +( 144 -176 48 ) ( 144 -48 80 ) ( 144 -176 80 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 96 -208 16 ) ( 96 -208 17 ) ( 97 -208 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 96 -208 16 ) ( 97 -208 16 ) ( 96 -207 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 -176 128 ) ( 176 -175 128 ) ( 177 -176 128 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 -176 32 ) ( 177 -176 32 ) ( 176 -176 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 -176 32 ) ( 176 -176 33 ) ( 176 -175 32 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 18 +{ +( 96 -208 16 ) ( 96 -207 16 ) ( 96 -208 17 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 96 -208 16 ) ( 96 -208 17 ) ( 97 -208 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 96 -208 16 ) ( 97 -208 16 ) ( 96 -207 16 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 -176 128 ) ( 176 -175 128 ) ( 177 -176 128 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 176 -176 32 ) ( 177 -176 32 ) ( 176 -176 33 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +( 112 -176 80 ) ( 112 -48 64 ) ( 112 -176 64 ) mapping_defaults/ProtoDarkGreen 0 0 0 0.25 0.25 +} +// brush 19 +{ +( 96 272 16 ) ( 96 273 16 ) ( 96 272 17 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 96 272 16 ) ( 96 272 17 ) ( 97 272 16 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 96 272 16 ) ( 97 272 16 ) ( 96 273 16 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 224 336 384 ) ( 224 337 384 ) ( 225 336 384 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 224 336 32 ) ( 225 336 32 ) ( 224 336 33 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 224 336 32 ) ( 224 336 33 ) ( 224 337 32 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +} +// brush 20 +{ +( 336 112 16 ) ( 336 113 16 ) ( 336 112 17 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 336 112 16 ) ( 336 112 17 ) ( 337 112 16 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 336 112 16 ) ( 337 112 16 ) ( 336 113 16 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 416 208 112 ) ( 416 209 112 ) ( 417 208 112 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 416 208 32 ) ( 417 208 32 ) ( 416 208 33 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 416 208 32 ) ( 416 208 33 ) ( 416 209 32 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +} +// brush 21 +{ +( 144 160 16 ) ( 144 161 16 ) ( 144 160 17 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 144 160 16 ) ( 144 160 17 ) ( 145 160 16 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 144 160 16 ) ( 145 160 16 ) ( 144 161 16 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 192 272 224 ) ( 192 273 224 ) ( 193 272 224 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 192 272 32 ) ( 193 272 32 ) ( 192 272 33 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 192 272 32 ) ( 192 272 33 ) ( 192 273 32 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +} +// brush 22 +{ +( 320 -224 128 ) ( 320 -223 128 ) ( 320 -224 129 ) mapping_defaults/ProtoGrey 128 0 0 0.25 0.25 +( 320 -224 128 ) ( 320 -224 129 ) ( 321 -224 128 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 320 -224 128 ) ( 321 -224 128 ) ( 320 -223 128 ) mapping_defaults/ProtoGrey 0 -128 0 0.25 0.25 +( 368 -160 144 ) ( 368 -159 144 ) ( 369 -160 144 ) mapping_defaults/ProtoGrey 0 -128 0 0.25 0.25 +( 368 -160 144 ) ( 369 -160 144 ) ( 368 -160 145 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 368 -160 144 ) ( 368 -160 145 ) ( 368 -159 144 ) mapping_defaults/ProtoGrey 128 0 0 0.25 0.25 +} +// brush 23 +{ +( 336 0 304 ) ( 336 1 304 ) ( 336 0 305 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 336 0 304 ) ( 336 0 305 ) ( 337 0 304 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 336 0 304 ) ( 337 0 304 ) ( 336 1 304 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 384 96 320 ) ( 384 97 320 ) ( 385 96 320 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 384 96 320 ) ( 385 96 320 ) ( 384 96 321 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +( 560 96 320 ) ( 560 96 321 ) ( 560 97 320 ) mapping_defaults/ProtoGrey 0 0 0 0.25 0.25 +} +// brush 24 +{ +( 17.071796769724585 1215.7128129211023 96 ) ( 49.07179676972447 1160.2871870788977 96 ) ( 49.07179676972447 1160.2871870788977 16 ) mapping_defaults/ProtoDark -222.7843 -48 0 0.8660254 1 +( 24 1219.7128129211023 16 ) ( 24 1219.7128129211023 96 ) ( 17.071796769724585 1215.7128129211023 96 ) mapping_defaults/ProtoDark -171.7128 -48 0 0.8660254 1 +( 56 1164.2871870788977 16 ) ( 24 1219.7128129211023 16 ) ( 17.071796769724585 1215.7128129211023 16 ) mapping_defaults/ProtoDark -113.64099 255.30194 30 1 1 +( 17.071796769724585 1215.7128129211023 96 ) ( 24 1219.7128129211023 96 ) ( 56 1164.2871870788977 96 ) mapping_defaults/ProtoDark -113.64099 255.30194 30 1 1 +( 49.07179676972447 1160.2871870788977 96 ) ( 56 1164.2871870788977 96 ) ( 56 1164.2871870788977 16 ) mapping_defaults/ProtoDark -171.66324 -48 0 0.8660254 1 +( 56 1164.2871870788977 96 ) ( 24 1219.7128129211023 96 ) ( 24 1219.7128129211023 16 ) mapping_defaults/ProtoDark -222.40308 -48 0 0.8660254 1 +} +// brush 25 +{ +( 1.3725830020305807 1241.3725830020303 96 ) ( 7.029437251522893 1235.7157287525379 96 ) ( 7.029437251522893 1235.7157287525379 16 ) mapping_defaults/ProtoDark 53.565918 -48 180 0.70710677 -1 +( 46.62741699796953 1286.6274169979697 96 ) ( 1.3725830020305807 1241.3725830020303 96 ) ( 1.3725830020305807 1241.3725830020303 16 ) mapping_defaults/ProtoDark -53.565918 -48 0 0.70710677 1 +( 7.029437251522893 1235.7157287525379 16 ) ( 52.28427124746196 1280.9705627484773 16 ) ( 46.62741699796953 1286.6274169979697 16 ) mapping_defaults/ProtoDark 120.81244 189.75354 315 1 1 +( 46.62741699796953 1286.6274169979697 96 ) ( 52.28427124746196 1280.9705627484773 96 ) ( 7.029437251522893 1235.7157287525379 96 ) mapping_defaults/ProtoDark 120.81244 189.75354 315 1 1 +( 52.28427124746196 1280.9705627484773 16 ) ( 52.28427124746196 1280.9705627484773 96 ) ( 46.62741699796953 1286.6274169979697 96 ) mapping_defaults/ProtoDark 53.565918 -48 180 0.70710677 -1 +( 7.029437251522893 1235.7157287525379 96 ) ( 52.28427124746196 1280.9705627484773 96 ) ( 52.28427124746196 1280.9705627484773 16 ) mapping_defaults/ProtoDark -53.565918 -48 0 0.70710677 1 +} +// brush 26 +{ +( 48 1280 16 ) ( 48 1281 16 ) ( 48 1280 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 48 1280 16 ) ( 48 1280 17 ) ( 49 1280 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 48 1280 16 ) ( 49 1280 16 ) ( 48 1281 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 200 1288 120 ) ( 200 1289 120 ) ( 201 1288 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 200 1288 24 ) ( 201 1288 24 ) ( 200 1288 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 200 1288 24 ) ( 200 1288 25 ) ( 200 1289 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 27 +{ +( 48 1264 96 ) ( 48 1265 96 ) ( 48 1264 97 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 48 1144 96 ) ( 48 1144 97 ) ( 49 1144 96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 48 1264 96 ) ( 49 1264 96 ) ( 48 1265 96 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 56 1280 120 ) ( 56 1281 120 ) ( 57 1280 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 56 1280 104 ) ( 57 1280 104 ) ( 56 1280 105 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 56 1280 104 ) ( 56 1280 105 ) ( 56 1281 104 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 28 +{ +( 48 1144 16 ) ( 48 1145 16 ) ( 48 1144 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 48 1144 16 ) ( 48 1144 17 ) ( 49 1144 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 48 1144 16 ) ( 49 1144 16 ) ( 48 1145 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 56 1160 96 ) ( 56 1161 96 ) ( 57 1160 96 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 56 1160 24 ) ( 57 1160 24 ) ( 56 1160 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 56 1160 24 ) ( 56 1160 25 ) ( 56 1161 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 29 +{ +( 48 1112 16 ) ( 48 1113 16 ) ( 48 1112 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 48 1112 16 ) ( 48 1112 17 ) ( 49 1112 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 48 1112 16 ) ( 49 1112 16 ) ( 48 1113 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 64 1144 120 ) ( 64 1145 120 ) ( 65 1144 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 64 1144 24 ) ( 65 1144 24 ) ( 64 1144 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 56 1144 24 ) ( 56 1144 25 ) ( 56 1145 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 30 +{ +( 248 1208 64 ) ( 200 1288 64 ) ( 200 1288 120 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 248 1208 120 ) ( 256 1202.6666666666606 120 ) ( 256 1202.6666666666579 64 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 256 1202.6666666666579 64 ) ( 256 1288 64 ) ( 200 1288 64 ) mapping_defaults/ProtoDark -80 223.99988 0 1 1 +( 200 1288 120 ) ( 256 1288 120 ) ( 256 1202.6666666666606 120 ) mapping_defaults/ProtoDark -80 223.99988 0 1 1 +( 256 1288 64 ) ( 256 1288 120 ) ( 200 1288 120 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 256 1202.6666666666606 120 ) ( 256 1288 120 ) ( 256 1288 64 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 31 +{ +( 200 1200 16 ) ( 200 1201 16 ) ( 200 1200 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 200 1240 96 ) ( 224 1224 224 ) ( 224 1224 96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 200 1200 16 ) ( 201 1200 16 ) ( 200 1201 16 ) mapping_defaults/ProtoDark -80 224.99988 0 1 1 +( 200 1240 64 ) ( 224 1352 64 ) ( 224 1224 64 ) mapping_defaults/ProtoDark -80 224.99988 0 1 1 +( 360 1288 24 ) ( 361 1288 24 ) ( 360 1288 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 256 1288 24 ) ( 256 1288 25 ) ( 256 1289 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 32 +{ +( 256 1200 16 ) ( 256 1201 16 ) ( 256 1200 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 256 1200 16 ) ( 256 1200 17 ) ( 257 1200 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 256 1200 16 ) ( 257 1200 16 ) ( 256 1201 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 264 1296 120 ) ( 264 1297 120 ) ( 265 1296 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 264 1288 24 ) ( 265 1288 24 ) ( 264 1288 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 272 1296 24 ) ( 272 1296 25 ) ( 272 1297 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 33 +{ +( 448 1200 16 ) ( 448 1201 16 ) ( 448 1200 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 440 1200 16 ) ( 440 1200 17 ) ( 441 1200 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 440 1200 16 ) ( 441 1200 16 ) ( 440 1201 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 448 1296 120 ) ( 448 1297 120 ) ( 449 1296 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 448 1288 24 ) ( 449 1288 24 ) ( 448 1288 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 456 1296 24 ) ( 456 1296 25 ) ( 456 1297 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 34 +{ +( 272 1200 112 ) ( 272 1201 112 ) ( 272 1200 113 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 272 1200 112 ) ( 272 1200 113 ) ( 273 1200 112 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 272 1200 112 ) ( 273 1200 112 ) ( 272 1201 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 280 1288 120 ) ( 280 1289 120 ) ( 281 1288 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 280 1288 120 ) ( 281 1288 120 ) ( 280 1288 121 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 448 1288 120 ) ( 448 1288 121 ) ( 448 1289 120 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 35 +{ +( 272 1200 96 ) ( 272 1201 96 ) ( 272 1200 97 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 272 1200 96 ) ( 272 1200 97 ) ( 273 1200 96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 272 1200 96 ) ( 273 1200 96 ) ( 272 1201 96 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 312 1208 112 ) ( 312 1209 112 ) ( 313 1208 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 312 1208 104 ) ( 313 1208 104 ) ( 312 1208 105 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 448 1208 104 ) ( 448 1208 105 ) ( 448 1209 104 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 36 +{ +( 264 1288 16 ) ( 264 1289 16 ) ( 264 1288 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 264 1288 16 ) ( 264 1288 17 ) ( 265 1288 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 264 1288 16 ) ( 265 1288 16 ) ( 264 1289 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 272 1344 120 ) ( 272 1345 120 ) ( 273 1344 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 272 1344 24 ) ( 273 1344 24 ) ( 272 1344 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 272 1344 24 ) ( 272 1344 25 ) ( 272 1345 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 37 +{ +( 272 1288 112 ) ( 272 1289 112 ) ( 272 1288 113 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 272 1288 112 ) ( 272 1288 113 ) ( 273 1288 112 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 272 1288 112 ) ( 273 1288 112 ) ( 272 1289 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 280 1344 120 ) ( 280 1345 120 ) ( 281 1344 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 280 1344 120 ) ( 281 1344 120 ) ( 280 1344 121 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 456 1344 120 ) ( 456 1344 121 ) ( 456 1345 120 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 38 +{ +( 272 1336 16 ) ( 272 1337 16 ) ( 272 1336 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 272 1336 16 ) ( 272 1336 17 ) ( 273 1336 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 272 1336 16 ) ( 273 1336 16 ) ( 272 1337 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 392 1344 112 ) ( 392 1345 112 ) ( 393 1344 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 392 1344 24 ) ( 393 1344 24 ) ( 392 1344 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 456 1344 24 ) ( 456 1344 25 ) ( 456 1345 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 39 +{ +( 56 1112 16 ) ( 56 1113 16 ) ( 56 1112 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 56 1112 16 ) ( 56 1112 17 ) ( 57 1112 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 56 1112 16 ) ( 57 1112 16 ) ( 56 1113 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 504 1120 120 ) ( 504 1121 120 ) ( 505 1120 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 504 1120 24 ) ( 505 1120 24 ) ( 504 1120 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 176 1112 80 ) ( 176 1112 88 ) ( 176 1240 88 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 40 +{ +( 176 1112 120 ) ( 176 1240 128 ) ( 176 1112 128 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 56 1112 56 ) ( 56 1112 57 ) ( 57 1112 56 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 56 1112 88 ) ( 57 1112 88 ) ( 56 1113 88 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 504 1120 128 ) ( 504 1121 128 ) ( 505 1120 128 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 504 1120 64 ) ( 505 1120 64 ) ( 504 1120 65 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 240 1112 104 ) ( 240 1112 112 ) ( 240 1240 112 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 41 +{ +( 240 1112 64 ) ( 240 1240 72 ) ( 240 1112 72 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 56 1112 16 ) ( 56 1112 17 ) ( 57 1112 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 56 1112 16 ) ( 57 1112 16 ) ( 56 1113 16 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 504 1120 128 ) ( 504 1121 128 ) ( 505 1120 128 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 504 1120 24 ) ( 505 1120 24 ) ( 504 1120 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 504 1120 24 ) ( 504 1120 25 ) ( 504 1121 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 42 +{ +( 496 904 16 ) ( 496 905 16 ) ( 496 904 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 496 896 16 ) ( 496 896 17 ) ( 497 896 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 496 904 16 ) ( 497 904 16 ) ( 496 905 16 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 504 1112 272 ) ( 504 1113 272 ) ( 505 1112 272 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 504 1120 24 ) ( 505 1120 24 ) ( 504 1120 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 504 1112 24 ) ( 504 1112 25 ) ( 504 1113 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 43 +{ +( 240 1120 120 ) ( 240 1121 120 ) ( 240 1120 121 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 240 1120 120 ) ( 240 1120 121 ) ( 241 1120 120 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 240 1120 120 ) ( 241 1120 120 ) ( 240 1121 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 456 1288 128 ) ( 456 1289 128 ) ( 457 1288 128 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 456 1288 128 ) ( 457 1288 128 ) ( 456 1288 129 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 456 1288 128 ) ( 456 1288 129 ) ( 456 1289 128 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 44 +{ +( 176 1008 224 ) ( 176 1009 224 ) ( 176 1008 225 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +( 184 1008 224 ) ( 184 1008 225 ) ( 185 1008 224 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 184 1008 224 ) ( 185 1008 224 ) ( 184 1009 224 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 496 1088 272 ) ( 496 1089 272 ) ( 497 1088 272 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 496 1116 232 ) ( 497 1116 232 ) ( 496 1116 233 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 496 1088 232 ) ( 496 1088 233 ) ( 496 1089 232 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +} +// brush 45 +{ +( 168 1056 16 ) ( 168 1057 16 ) ( 168 1056 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 168 696 16 ) ( 168 696 17 ) ( 169 696 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 912 248 ) ( 304 936 248 ) ( 176 936 248 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 1112 272 ) ( 176 1113 272 ) ( 177 1112 272 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 1116 24 ) ( 177 1116 24 ) ( 176 1116 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 1112 24 ) ( 176 1112 25 ) ( 176 1113 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 46 +{ +( 168 1056 16 ) ( 168 1057 16 ) ( 168 1056 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 176 952 216 ) ( 176 952 232 ) ( 304 952 232 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 912 208 ) ( 304 936 208 ) ( 176 936 208 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 912 248 ) ( 176 936 248 ) ( 304 936 248 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 1116 24 ) ( 177 1116 24 ) ( 176 1116 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 1112 24 ) ( 176 1112 25 ) ( 176 1113 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 47 +{ +( 168 1056 16 ) ( 168 1057 16 ) ( 168 1056 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 176 872 216 ) ( 176 872 224 ) ( 304 872 224 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 912 208 ) ( 304 936 208 ) ( 176 936 208 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 912 248 ) ( 176 936 248 ) ( 304 936 248 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 912 216 ) ( 304 912 224 ) ( 176 912 224 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 1112 24 ) ( 176 1112 25 ) ( 176 1113 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 48 +{ +( 168 1056 16 ) ( 168 1057 16 ) ( 168 1056 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 176 784 216 ) ( 176 784 224 ) ( 304 784 224 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 912 208 ) ( 304 936 208 ) ( 176 936 208 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 912 248 ) ( 176 936 248 ) ( 304 936 248 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 832 216 ) ( 304 832 232 ) ( 176 832 232 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 1112 24 ) ( 176 1112 25 ) ( 176 1113 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 49 +{ +( 168 1056 16 ) ( 168 1057 16 ) ( 168 1056 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 168 696 16 ) ( 168 696 17 ) ( 169 696 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 912 208 ) ( 304 936 208 ) ( 176 936 208 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 912 248 ) ( 176 936 248 ) ( 304 936 248 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 744 224 ) ( 304 744 232 ) ( 176 744 232 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 1112 24 ) ( 176 1112 25 ) ( 176 1113 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 50 +{ +( 176 912 264 ) ( 176 913 264 ) ( 176 912 265 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 176 656 264 ) ( 176 656 265 ) ( 177 656 264 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 176 912 264 ) ( 177 912 264 ) ( 176 913 264 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 496 1008 272 ) ( 496 1009 272 ) ( 497 1008 272 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 496 1008 272 ) ( 497 1008 272 ) ( 496 1008 273 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 368 1008 272 ) ( 368 1008 273 ) ( 368 1009 272 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 51 +{ +( 168 1056 16 ) ( 168 1057 16 ) ( 168 1056 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 168 696 16 ) ( 168 696 17 ) ( 169 696 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 720 112 ) ( 304 784 112 ) ( 176 784 112 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 912 208 ) ( 176 936 208 ) ( 304 936 208 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 1116 24 ) ( 177 1116 24 ) ( 176 1116 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 1112 24 ) ( 176 1112 25 ) ( 176 1113 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 52 +{ +( 168 1056 16 ) ( 168 1057 16 ) ( 168 1056 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 168 696 16 ) ( 168 696 17 ) ( 169 696 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 168 1056 16 ) ( 169 1056 16 ) ( 168 1057 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 176 720 112 ) ( 176 784 112 ) ( 304 784 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 176 728 32 ) ( 304 728 40 ) ( 176 728 40 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 176 1112 24 ) ( 176 1112 25 ) ( 176 1113 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 53 +{ +( 168 1056 16 ) ( 168 1057 16 ) ( 168 1056 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 176 816 40 ) ( 176 816 56 ) ( 304 816 56 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 168 1056 16 ) ( 169 1056 16 ) ( 168 1057 16 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 720 112 ) ( 176 784 112 ) ( 304 784 112 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 1112 24 ) ( 177 1112 24 ) ( 176 1112 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 1112 24 ) ( 176 1112 25 ) ( 176 1113 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 54 +{ +( 168 656 16 ) ( 168 657 16 ) ( 168 656 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 168 656 16 ) ( 168 656 17 ) ( 169 656 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 168 656 16 ) ( 169 656 16 ) ( 168 657 16 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 696 272 ) ( 176 697 272 ) ( 177 696 272 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 176 696 24 ) ( 177 696 24 ) ( 176 696 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 176 696 24 ) ( 176 696 25 ) ( 176 697 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 55 +{ +( 496 656 264 ) ( 496 657 264 ) ( 496 656 265 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 496 656 264 ) ( 496 656 265 ) ( 497 656 264 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 496 656 184 ) ( 497 656 184 ) ( 496 657 184 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 504 896 272 ) ( 504 897 272 ) ( 505 896 272 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 504 896 272 ) ( 505 896 272 ) ( 504 896 273 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 504 896 272 ) ( 504 896 273 ) ( 504 897 272 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 56 +{ +( 168 640 16 ) ( 168 641 16 ) ( 168 640 17 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 168 648 16 ) ( 168 648 17 ) ( 169 648 16 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 168 640 16 ) ( 169 640 16 ) ( 168 641 16 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 536 656 272 ) ( 536 657 272 ) ( 537 656 272 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 536 656 24 ) ( 537 656 24 ) ( 536 656 25 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 536 656 24 ) ( 536 656 25 ) ( 536 657 24 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 57 +{ +( 496 656 176 ) ( 496 657 176 ) ( 496 656 177 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +( 496 656 176 ) ( 496 656 177 ) ( 497 656 176 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 496 656 16 ) ( 497 656 16 ) ( 496 657 16 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 504 664 184 ) ( 504 665 184 ) ( 505 664 184 ) mapping_defaults/ProtoOrange -80 224 0 1 1 +( 504 728 184 ) ( 505 728 184 ) ( 504 728 185 ) mapping_defaults/ProtoOrange -80 -48 0 1 1 +( 504 664 184 ) ( 504 664 185 ) ( 504 665 184 ) mapping_defaults/ProtoOrange -224 -48 0 1 1 +} +// brush 58 +{ +( 176 688 128 ) ( 176 689 128 ) ( 176 688 129 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 176 656 128 ) ( 176 656 129 ) ( 177 656 128 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 176 688 128 ) ( 177 688 128 ) ( 176 689 128 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 240 872 136 ) ( 240 873 136 ) ( 241 872 136 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 240 944 136 ) ( 241 944 136 ) ( 240 944 137 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 264 872 136 ) ( 264 872 137 ) ( 264 873 136 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 59 +{ +( 260 860 136 ) ( 260 861 136 ) ( 260 860 137 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 260 704 136 ) ( 260 704 137 ) ( 261 704 136 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 260 860 136 ) ( 261 860 136 ) ( 260 861 136 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 264 992 164 ) ( 264 993 164 ) ( 265 992 164 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 264 944 140 ) ( 265 944 140 ) ( 264 944 141 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 264 992 140 ) ( 264 992 141 ) ( 264 993 140 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 60 +{ +( 240 1040 192 ) ( 240 1048 184 ) ( 240 1048 312 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +( 200 1028 204 ) ( 204 1028 332 ) ( 204 1028 204 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 168 1088 144 ) ( 168 1080 152 ) ( 296 1080 152 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 296 1120 224 ) ( 296 1121 224 ) ( 297 1120 224 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 192 1060 172 ) ( 212 1060 172 ) ( 212 1060 300 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 496 1120 136 ) ( 496 1120 137 ) ( 496 1121 136 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +} +// brush 61 +{ +( 176 960 128 ) ( 176 961 128 ) ( 176 960 129 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +( 192 1060 172 ) ( 212 1060 300 ) ( 212 1060 172 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 168 1088 144 ) ( 168 1080 152 ) ( 296 1080 152 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 176 960 128 ) ( 177 960 128 ) ( 176 961 128 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 296 1120 176 ) ( 296 1121 176 ) ( 297 1120 176 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 296 1120 136 ) ( 297 1120 136 ) ( 296 1120 137 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 236 1060 172 ) ( 236 1060 176 ) ( 236 1188 176 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +} +// brush 62 +{ +( 240 1024 208 ) ( 240 1020 340 ) ( 240 1020 212 ) mapping_defaults/ProtoBrightBlue -223.99994 -48.000015 0 1 1 +( 168 1088 144 ) ( 168 1080 152 ) ( 296 1080 152 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 296 1120 224 ) ( 296 1121 224 ) ( 297 1120 224 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 200 1028 204 ) ( 204 1028 204 ) ( 204 1028 332 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 496 1120 136 ) ( 496 1120 137 ) ( 496 1121 136 ) mapping_defaults/ProtoBrightBlue -223.99994 -48.000015 0 1 1 +} +// brush 63 +{ +( 176 960 128 ) ( 176 961 128 ) ( 176 960 129 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +( 168 1088 144 ) ( 168 1080 152 ) ( 296 1080 152 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 296 1120 224 ) ( 296 1121 224 ) ( 297 1120 224 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 176 1020 212 ) ( 184 1020 212 ) ( 184 1020 340 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 240 1024 208 ) ( 240 1020 212 ) ( 240 1020 340 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +} +// brush 64 +{ +( 236 1060 172 ) ( 236 1188 176 ) ( 236 1060 176 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +( 192 1060 172 ) ( 212 1060 300 ) ( 212 1060 172 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 168 1088 144 ) ( 168 1080 152 ) ( 296 1080 152 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 176 960 128 ) ( 177 960 128 ) ( 176 961 128 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 240 1120 176 ) ( 248 1248 176 ) ( 248 1120 176 ) mapping_defaults/ProtoBrightBlue -80 224 0 1 1 +( 296 1120 136 ) ( 297 1120 136 ) ( 296 1120 137 ) mapping_defaults/ProtoBrightBlue -80 -48 0 1 1 +( 496 1120 136 ) ( 496 1120 137 ) ( 496 1121 136 ) mapping_defaults/ProtoBrightBlue -224 -48 0 1 1 +} +// brush 65 +{ +( 304 656 16 ) ( 292 656 8 ) ( 292 784 8 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 88 656 20 ) ( 88 656 21 ) ( 89 656 20 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 88 688 -169.33333333333326 ) ( 89 688 -169.33333333333326 ) ( 88 689 -169.33333333333326 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 208 704 24 ) ( 209 704 24 ) ( 208 704 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 160 656 -92 ) ( 172 656 -84 ) ( 172 784 -84 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 304 704 24 ) ( 304 704 25 ) ( 304 705 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 66 +{ +( -108 656 -172 ) ( -108 657 -172 ) ( -108 656 -171 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 108 656 -172 ) ( 108 656 -171 ) ( 109 656 -172 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 108 656 -172 ) ( 109 656 -172 ) ( 108 657 -172 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 120 700 -168 ) ( 120 701 -168 ) ( 121 700 -168 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 120 984 -168 ) ( 121 984 -168 ) ( 120 984 -167 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 320 700 -168 ) ( 320 700 -167 ) ( 320 701 -168 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 67 +{ +( -112 984 -96 ) ( -112 985 -96 ) ( -112 984 -95 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( -96 984 -96 ) ( -96 984 -95 ) ( -95 984 -96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( -96 984 -172 ) ( -95 984 -172 ) ( -96 985 -172 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( -20 988 4 ) ( -20 989 4 ) ( -19 988 4 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( -20 988 -92 ) ( -19 988 -92 ) ( -20 988 -91 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 320 988 -92 ) ( 320 988 -91 ) ( 320 989 -92 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 68 +{ +( 316 956 -96 ) ( 316 957 -96 ) ( 316 956 -95 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 316 640 -96 ) ( 316 640 -95 ) ( 317 640 -96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 316 956 -172 ) ( 317 956 -172 ) ( 316 957 -172 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 320 972 4 ) ( 320 973 4 ) ( 321 972 4 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 320 992 -92 ) ( 321 992 -92 ) ( 320 992 -91 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 320 972 -92 ) ( 320 972 -91 ) ( 320 973 -92 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 69 +{ +( -112 980 -96 ) ( -112 981 -96 ) ( -112 980 -95 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( -112 656 -96 ) ( -112 656 -95 ) ( -111 656 -96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( -112 980 -172 ) ( -111 980 -172 ) ( -112 981 -172 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( -108 984 4 ) ( -108 985 4 ) ( -107 984 4 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( -108 984 -92 ) ( -107 984 -92 ) ( -108 984 -91 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( -108 984 -92 ) ( -108 984 -91 ) ( -108 985 -92 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 70 +{ +( -168 700 4 ) ( -168 701 4 ) ( -168 700 5 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 160 656 4 ) ( 160 656 5 ) ( 161 656 4 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 160 700 4 ) ( 161 700 4 ) ( 160 701 4 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 176 704 8 ) ( 176 705 8 ) ( 177 704 8 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 176 704 8 ) ( 177 704 8 ) ( 176 704 9 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 124 704 8 ) ( 124 704 9 ) ( 124 705 8 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 71 +{ +( -112 652 -96 ) ( -112 653 -96 ) ( -112 652 -95 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( -112 652 -96 ) ( -112 652 -95 ) ( -111 652 -96 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( -112 652 -172 ) ( -111 652 -172 ) ( -112 653 -172 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 176 656 4 ) ( 176 657 4 ) ( 177 656 4 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 176 656 -92 ) ( 177 656 -92 ) ( 176 656 -91 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 320 656 -92 ) ( 320 656 -91 ) ( 320 657 -92 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 72 +{ +( 264 656 16 ) ( 264 657 16 ) ( 264 656 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 276 704 120 ) ( 288 704 112 ) ( 288 832 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 360 656 16 ) ( 360 656 17 ) ( 361 656 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 360 656 16 ) ( 361 656 16 ) ( 360 657 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 488 704 20 ) ( 489 704 20 ) ( 488 704 21 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 264 676 136 ) ( 276 804 128 ) ( 276 676 128 ) mapping_defaults/ProtoDark -80 224 0 1 1 +} +// brush 73 +{ +( 272 1200 16 ) ( 272 1201 16 ) ( 272 1200 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 272 1200 16 ) ( 272 1200 17 ) ( 273 1200 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 272 1200 16 ) ( 273 1200 16 ) ( 272 1201 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 444 1232 44 ) ( 428 1232 44 ) ( 428 1360 44 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 280 1216 24 ) ( 281 1216 24 ) ( 280 1216 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 448 1232 24 ) ( 448 1232 25 ) ( 448 1233 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 74 +{ +( 272 1200 16 ) ( 272 1201 16 ) ( 272 1200 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 272 1200 16 ) ( 272 1200 17 ) ( 273 1200 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 444 1232 44 ) ( 428 1360 44 ) ( 428 1232 44 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 280 1232 56 ) ( 280 1233 56 ) ( 281 1232 56 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 280 1232 24 ) ( 281 1232 24 ) ( 280 1232 25 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 448 1232 24 ) ( 448 1232 25 ) ( 448 1233 24 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 75 +{ +( 272 1216 28 ) ( 272 1217 28 ) ( 272 1216 29 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 272 1216 28 ) ( 272 1216 29 ) ( 273 1216 28 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 272 1216 28 ) ( 273 1216 28 ) ( 272 1217 28 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 448 1236 32 ) ( 448 1237 32 ) ( 449 1236 32 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 448 1232 32 ) ( 449 1232 32 ) ( 448 1232 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 448 1236 32 ) ( 448 1236 33 ) ( 448 1237 32 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 76 +{ +( 236 1172 120 ) ( 236 1173 120 ) ( 236 1172 121 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 228 1120 120 ) ( 228 1120 121 ) ( 229 1120 120 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 228 1172 120 ) ( 229 1172 120 ) ( 228 1173 120 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 240 1284 272 ) ( 240 1285 272 ) ( 241 1284 272 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 240 1288 124 ) ( 241 1288 124 ) ( 240 1288 125 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 240 1284 124 ) ( 240 1284 125 ) ( 240 1285 124 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 77 +{ +( 240 1284 128 ) ( 240 1285 128 ) ( 240 1284 129 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 240 1284 128 ) ( 240 1284 129 ) ( 241 1284 128 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 240 1284 128 ) ( 241 1284 128 ) ( 240 1285 128 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 452 1288 216 ) ( 452 1289 216 ) ( 453 1288 216 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 452 1288 132 ) ( 453 1288 132 ) ( 452 1288 133 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 456 1288 132 ) ( 456 1288 133 ) ( 456 1289 132 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 78 +{ +( 168 1120 176 ) ( 168 1121 176 ) ( 168 1120 177 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 244 1116 176 ) ( 244 1116 177 ) ( 245 1116 176 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 244 1120 176 ) ( 245 1120 176 ) ( 244 1121 176 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 348 1124 272 ) ( 348 1125 272 ) ( 349 1124 272 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 348 1124 180 ) ( 349 1124 180 ) ( 348 1124 181 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 496 1124 180 ) ( 496 1124 181 ) ( 496 1125 180 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 79 +{ +( 688 912 16 ) ( 688 913 16 ) ( 688 912 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 688 912 16 ) ( 688 912 17 ) ( 689 912 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 688 912 16 ) ( 689 912 16 ) ( 688 913 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 704 1136 272 ) ( 704 1137 272 ) ( 705 1136 272 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 704 1136 32 ) ( 705 1136 32 ) ( 704 1136 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 704 1136 32 ) ( 704 1136 33 ) ( 704 1137 32 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 80 +{ +( 592 1216 16 ) ( 592 1217 16 ) ( 592 1216 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 592 1216 16 ) ( 592 1216 17 ) ( 593 1216 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 592 1216 16 ) ( 593 1216 16 ) ( 592 1217 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 800 1232 288 ) ( 800 1233 288 ) ( 801 1232 288 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 800 1232 32 ) ( 801 1232 32 ) ( 800 1232 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 800 1232 32 ) ( 800 1232 33 ) ( 800 1233 32 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 81 +{ +( 1024 896 176 ) ( 1008 896 160 ) ( 1008 1024 160 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 832 896 16 ) ( 832 896 17 ) ( 833 896 16 ) mapping_defaults/ProtoDark -80 -47.999992 0 1 1 +( 832 896 16 ) ( 833 896 16 ) ( 832 897 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1040 976 32 ) ( 1041 976 32 ) ( 1040 976 33 ) mapping_defaults/ProtoDark -80 -47.999992 0 1 1 +( 1072 944 32 ) ( 1072 944 33 ) ( 1072 945 32 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 82 +{ +( 1072 896 48 ) ( 1072 897 48 ) ( 1072 896 49 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 1040 896 48 ) ( 1040 896 49 ) ( 1041 896 48 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1056 896 176 ) ( 1088 896 176 ) ( 1088 1024 176 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 976 224 ) ( 1136 977 224 ) ( 1137 976 224 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 976 64 ) ( 1137 976 64 ) ( 1136 976 65 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1136 976 64 ) ( 1136 976 65 ) ( 1136 977 64 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 83 +{ +( 1056 976 112 ) ( 1056 976 96 ) ( 1056 1104 96 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 864 976 16 ) ( 864 976 17 ) ( 865 976 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1056 976 112 ) ( 1088 976 112 ) ( 1088 1104 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 1056 496 ) ( 1136 1057 496 ) ( 1137 1056 496 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 1056 32 ) ( 1137 1056 32 ) ( 1136 1056 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1136 1056 32 ) ( 1136 1056 33 ) ( 1136 1057 32 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 84 +{ +( 864 976 16 ) ( 864 977 16 ) ( 864 976 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 864 976 16 ) ( 864 976 17 ) ( 865 976 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 864 976 16 ) ( 865 976 16 ) ( 864 977 16 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1056 976 112 ) ( 1040 976 112 ) ( 1040 1104 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 1056 32 ) ( 1137 1056 32 ) ( 1136 1056 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 960 976 112 ) ( 960 1104 96 ) ( 960 976 96 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 85 +{ +( 864 976 16 ) ( 864 977 16 ) ( 864 976 17 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 864 976 16 ) ( 864 976 17 ) ( 865 976 16 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1056 976 112 ) ( 1040 1104 112 ) ( 1040 976 112 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 1056 496 ) ( 1136 1057 496 ) ( 1137 1056 496 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 1056 32 ) ( 1137 1056 32 ) ( 1136 1056 33 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1056 976 112 ) ( 1056 1104 96 ) ( 1056 976 96 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 86 +{ +( 1136 896 208 ) ( 1136 897 208 ) ( 1136 896 209 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 1136 896 208 ) ( 1136 896 209 ) ( 1137 896 208 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1136 896 208 ) ( 1137 896 208 ) ( 1136 897 208 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1152 928 224 ) ( 1152 929 224 ) ( 1153 928 224 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1152 1136 224 ) ( 1153 1136 224 ) ( 1152 1136 225 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1200 928 224 ) ( 1200 928 225 ) ( 1200 929 224 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 87 +{ +( 880 1056 208 ) ( 880 1057 208 ) ( 880 1056 209 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 1120 1056 208 ) ( 1120 1056 209 ) ( 1121 1056 208 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1120 1056 208 ) ( 1121 1056 208 ) ( 1120 1057 208 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 1136 224 ) ( 1137 1136 224 ) ( 1136 1136 225 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 1136 1136 224 ) ( 1072 1136 240 ) ( 1072 1264 240 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 1136 1120 224 ) ( 1136 1120 225 ) ( 1136 1121 224 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 88 +{ +( 784 1056 208 ) ( 784 1057 208 ) ( 784 1056 209 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +( 784 1056 208 ) ( 784 1056 209 ) ( 785 1056 208 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 784 1056 208 ) ( 785 1056 208 ) ( 784 1057 208 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 864 1136 288 ) ( 864 1137 288 ) ( 865 1136 288 ) mapping_defaults/ProtoDark -80 224 0 1 1 +( 864 1136 224 ) ( 865 1136 224 ) ( 864 1136 225 ) mapping_defaults/ProtoDark -80 -48 0 1 1 +( 880 1136 224 ) ( 880 1136 225 ) ( 880 1137 224 ) mapping_defaults/ProtoDark -224 -48 0 1 1 +} +// brush 89 +{ +( -32 640 16 ) ( -32 641 16 ) ( -32 640 17 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( -32 640 16 ) ( -32 640 17 ) ( -31 640 16 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( -32 640 16 ) ( -31 640 16 ) ( -32 641 16 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( 16 784 208 ) ( 16 785 208 ) ( 17 784 208 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( 16 784 32 ) ( 17 784 32 ) ( 16 784 33 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( 16 784 32 ) ( 16 784 33 ) ( 16 785 32 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +} +// brush 90 +{ +( -48 864 16 ) ( -48 865 16 ) ( -48 864 17 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( -48 864 16 ) ( -48 864 17 ) ( -47 864 16 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( -48 864 16 ) ( -47 864 16 ) ( -48 865 16 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( 16 1008 304 ) ( 16 1009 304 ) ( 17 1008 304 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( 16 1008 32 ) ( 17 1008 32 ) ( 16 1008 33 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( 16 1008 32 ) ( 16 1008 33 ) ( 16 1009 32 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +} +// brush 91 +{ +( -224 496 16 ) ( -224 497 16 ) ( -224 496 17 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( -224 496 16 ) ( -224 496 17 ) ( -223 496 16 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( -224 496 16 ) ( -223 496 16 ) ( -224 497 16 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( 32 544 224 ) ( 32 545 224 ) ( 33 544 224 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( 32 544 32 ) ( 33 544 32 ) ( 32 544 33 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( 32 544 32 ) ( 32 544 33 ) ( 32 545 32 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +} +// brush 92 +{ +( -160 528 144 ) ( -160 529 144 ) ( -160 528 145 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( -160 528 144 ) ( -160 528 145 ) ( -159 528 144 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( -160 528 144 ) ( -159 528 144 ) ( -160 529 144 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( -32 544 160 ) ( -32 545 160 ) ( -31 544 160 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( -32 992 160 ) ( -31 992 160 ) ( -32 992 161 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +( -32 544 160 ) ( -32 544 161 ) ( -32 545 160 ) mapping_defaults/ProtoEmerald 0 0 0 0.25 0.25 +} +} +// entity 1 +{ +"classname" "enemy_spawn" +"origin" "-64 -48 40" +} +// entity 2 +{ +"classname" "info_player_start" +"origin" "-96 128 40" +} +// entity 3 +{ +"classname" "enemy_spawn" +"origin" "120 1216 40" +} diff --git a/projects/content/textures/mapping_defaults/ProtoBrightBlue.png b/projects/content/textures/mapping_defaults/ProtoBrightBlue.png new file mode 100644 index 0000000..e4f20f8 Binary files /dev/null and b/projects/content/textures/mapping_defaults/ProtoBrightBlue.png differ diff --git a/projects/content/textures/mapping_defaults/ProtoDark.png b/projects/content/textures/mapping_defaults/ProtoDark.png new file mode 100644 index 0000000..bd12bed Binary files /dev/null and b/projects/content/textures/mapping_defaults/ProtoDark.png differ diff --git a/projects/content/textures/mapping_defaults/ProtoDarkBlue.png b/projects/content/textures/mapping_defaults/ProtoDarkBlue.png new file mode 100644 index 0000000..2aa8518 Binary files /dev/null and b/projects/content/textures/mapping_defaults/ProtoDarkBlue.png differ diff --git a/projects/content/textures/mapping_defaults/ProtoDarkGreen.png b/projects/content/textures/mapping_defaults/ProtoDarkGreen.png new file mode 100644 index 0000000..33feed9 Binary files /dev/null and b/projects/content/textures/mapping_defaults/ProtoDarkGreen.png differ diff --git a/projects/content/textures/mapping_defaults/ProtoEmerald.png b/projects/content/textures/mapping_defaults/ProtoEmerald.png new file mode 100644 index 0000000..324dad5 Binary files /dev/null and b/projects/content/textures/mapping_defaults/ProtoEmerald.png differ diff --git a/projects/content/textures/mapping_defaults/ProtoGreen.png b/projects/content/textures/mapping_defaults/ProtoGreen.png new file mode 100644 index 0000000..d2172a3 Binary files /dev/null and b/projects/content/textures/mapping_defaults/ProtoGreen.png differ diff --git a/projects/content/textures/mapping_defaults/ProtoGrey.aseprite b/projects/content/textures/mapping_defaults/ProtoGrey.aseprite new file mode 100644 index 0000000..d473310 Binary files /dev/null and b/projects/content/textures/mapping_defaults/ProtoGrey.aseprite differ diff --git a/projects/content/textures/mapping_defaults/ProtoGrey.png b/projects/content/textures/mapping_defaults/ProtoGrey.png new file mode 100644 index 0000000..274a276 Binary files /dev/null and b/projects/content/textures/mapping_defaults/ProtoGrey.png differ diff --git a/projects/content/textures/mapping_defaults/ProtoLime.png b/projects/content/textures/mapping_defaults/ProtoLime.png new file mode 100644 index 0000000..0e70744 Binary files /dev/null and b/projects/content/textures/mapping_defaults/ProtoLime.png differ diff --git a/projects/content/textures/mapping_defaults/ProtoMaroon.png b/projects/content/textures/mapping_defaults/ProtoMaroon.png new file mode 100644 index 0000000..213e184 Binary files /dev/null and b/projects/content/textures/mapping_defaults/ProtoMaroon.png differ diff --git a/projects/content/textures/mapping_defaults/ProtoOrange.png b/projects/content/textures/mapping_defaults/ProtoOrange.png new file mode 100644 index 0000000..aa9e90f Binary files /dev/null and b/projects/content/textures/mapping_defaults/ProtoOrange.png differ diff --git a/projects/content/textures/mapping_defaults/ProtoWhite.png b/projects/content/textures/mapping_defaults/ProtoWhite.png new file mode 100644 index 0000000..b4c6ab9 Binary files /dev/null and b/projects/content/textures/mapping_defaults/ProtoWhite.png differ diff --git a/projects/content/textures/mapping_defaults/ProtoYellow.png b/projects/content/textures/mapping_defaults/ProtoYellow.png new file mode 100644 index 0000000..8dfe8cf Binary files /dev/null and b/projects/content/textures/mapping_defaults/ProtoYellow.png differ diff --git a/projects/sampleGame/empire.zig b/projects/sampleGame/empire.zig index 7509e3f..87d4047 100644 --- a/projects/sampleGame/empire.zig +++ b/projects/sampleGame/empire.zig @@ -31,6 +31,7 @@ pub fn create(alloc: std.mem.Allocator) !*@This() { const lostEmpire = try core.createEntity(); const scene = lostEmpire.addComponent(core.Scene).?; scene.setPosition(.{ .y = -20 }); + _ = scene.getAndResolveTransform(); const empireMesh = lostEmpire.addComponent(rend.MeshComponent).?; empireMesh.setMesh("m_empire"); empireMesh.setTexture("t_empire"); diff --git a/projects/sampleGame/main.zig b/projects/sampleGame/main.zig index 03dfe8c..a414b07 100644 --- a/projects/sampleGame/main.zig +++ b/projects/sampleGame/main.zig @@ -24,6 +24,12 @@ videoFullbright: bool = false, moveLight: bool = true, +rendererDebugger: *extras.RendererDebug = undefined, + +tbMap: ?*bsp.maploader.TBMap = null, + +fileWatch: f64 = 3.0, + pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This()); pub fn init(allocator: std.mem.Allocator) !*@This() { @@ -140,6 +146,32 @@ pub const DamagedHelmet = struct { } }; +pub fn loadMap2(self: *@This()) !void { + if (self.tbMap) |tbMap| { + core.engine_log("killing the map", .{}); + tbMap.destroy(); + } + + self.tbMap = try bsp.maploader.LoadTrenchbroomMap(self.allocator, .{ + .rotation = core.Rotation.eulerX(core.radians(-90.0)), + .mapName = "bsp/testmap.map", + }); + + core.engine_log("map loaded", .{}); +} + +pub fn loadMap(self: *@This()) void { + self.tbMap = bsp.maploader.LoadTrenchbroomMap(self.allocator, .{ + .rotation = core.Rotation.eulerX(core.radians(-90.0)), + .mapName = "bsp/testmap.map", + }) catch |err| { + core.engine_log("unable to load map, error: {any}", .{err}); + self.tbMap = null; + return; + }; + core.engine_log("map loaded", .{}); +} + pub fn prepare(self: *@This()) !void { core.engine_log(">>>>>>> game prepare", .{}); var z = core.tracy.ZoneN(@src(), "PREPARING GAME"); @@ -148,6 +180,8 @@ pub fn prepare(self: *@This()) !void { try script.loadTypes("scripts"); try script.runScriptFile("scripts/prepare.lua"); + self.rendererDebugger = try extras.RendererDebug.create(self.allocator); //try core.createObject(extras.RendererDebug, .{}); + self.objectSpawner = try extras.ObjectSpawner.create(self.allocator); try self.objectSpawner.addSpawnFunction("fox", FoxObject); try self.objectSpawner.addSpawnFunction("doomplayer", DoomPlayer.DoomCanvas); @@ -330,14 +364,21 @@ pub fn getMouseMovement(self: *@This()) core.Vector2f { pub fn tick(self: *@This(), dt: f64) void { const fdt: f32 = @floatCast(dt); - const z = tracy.ZoneN(@src(), "tick sampleGameMain"); - defer z.End(); + _ = ig.dockSpaceOverViewport(ig.getMainViewport(), .{ .passthru_central_node = true }, null); + + self.fileWatch -= dt; + if (self.fileWatch < 0) { + self.fileWatch = 3.0; + } const z1 = tracy.ZoneN(@src(), "inputDebugger"); - extras.inputDebugger.tick(); + if (!self.mouseLook) { + extras.inputDebugger.tick(); + } z1.End(); const z2 = tracy.ZoneN(@src(), "inputDebugger"); + self.objectSpawner.windowOpen = !self.mouseLook; self.objectSpawner.tick(dt); z2.End(); @@ -349,6 +390,10 @@ pub fn tick(self: *@This(), dt: f64) void { self.fpcamera.tick(dt); z4.End(); + const z5 = tracy.ZoneN(@src(), ""); + DoomPlayer.maybeTick(dt); + z5.End(); + var movement = self.fpcamera.getForwardXZ().fmul(self.moveVector.z * fdt * self.cameraSpeed); movement = movement.add(self.fpcamera.getRightXZ().fmul(self.moveVector.x * fdt * self.cameraSpeed)); movement = movement.add(.{ .y = self.verticalMove * fdt * self.cameraSpeed }); @@ -373,29 +418,60 @@ pub fn tick(self: *@This(), dt: f64) void { rend.context().lightPosition = debugCenter; } + // self.loadMap2() catch unreachable; // show a window with the current camera's position - if (ig.begin("meh", &self.showWindow, .{})) { - ig.textFmt("x:{d:.03} y:{d:.03} z:{d:.03}", .{ pos.x, pos.y, pos.z }) catch return; - if (ig.checkbox("video fullbright", &self.videoFullbright)) { - if (self.videoplayerObject.fetch(rend.MeshComponent)) |mesh| { - mesh.textureMode.fullbright = self.videoFullbright; + if (!self.mouseLook) { + self.rendererDebugger.tick(dt); + if (ig.begin("meh", null, .{})) { + ig.textFmt("x:{d:.03} y:{d:.03} z:{d:.03}", .{ pos.x, pos.y, pos.z }) catch return; + if (ig.checkbox("video fullbright", &self.videoFullbright)) { + if (self.videoplayerObject.fetch(rend.MeshComponent)) |mesh| { + mesh.textureMode.fullbright = self.videoFullbright; + } + } + + if (ig.checkbox("move lights ", &self.moveLight)) {} + + ig.textFmt("info: - WASD to move, mouse to look,\n- Q and E to go up and down", .{}) catch return; + ig.textFmt("- shift to slow down camera speed", .{}) catch return; + ig.textFmt("- T to enable/disable mouse cursor", .{}) catch return; + ig.textFmt("- f2 to route all inputs to the doom player", .{}) catch return; + ig.textFmt("- movingLight checkbox makes the light stop moving with you", .{}) catch return; + + if (ig.smallButton("reload map")) { + self.loadMap2() catch unreachable; + } + + if (ig.smallButton("destroy map")) { + if (self.tbMap) |tbMap| { + core.engine_log("killing the map", .{}); + tbMap.destroy(); + self.tbMap = null; + } } } + ig.end(); - if (ig.checkbox("move lights ", &self.moveLight)) {} + if (ig.begin("mesh components", null, .{})) { + for (rend.MeshComponent.BaseContainer.dense.items) |*v| { + ig.textFmt("mesh: {s}", .{v.value.meshName.utf8()}) catch unreachable; + } + } + ig.end(); - ig.textFmt("info: - WASD to move, mouse to look,\n- Q and E to go up and down", .{}) catch return; - ig.textFmt("- shift to slow down camera speed", .{}) catch return; - ig.textFmt("- T to enable/disable mouse cursor", .{}) catch return; - ig.textFmt("- f2 to route all inputs to the doom player", .{}) catch return; - ig.textFmt("- movingLight checkbox makes the light stop moving with you", .{}) catch return; + if (ig.begin("scene components", null, .{})) { + for (core.Scene.BaseContainer.dense.items) |*v| { + ig.textFmt("scene entity: {d}", .{v.value.handle.index}) catch unreachable; + } + } ig.end(); } } pub fn deinit(self: *@This()) void { - // self.doomplayer.destroy(); + self.rendererDebugger.destroy(); + DoomPlayer.DoomCanvas.cleanupDoom(); self.fpcamera.destroy(); self.objectSpawner.destroy(); @@ -417,6 +493,8 @@ pub fn main() anyerror!void { const DoomPlayer = @import("doomplayer"); const VideoPlayer = @import("videoplayer"); const extras = @import("gameExtras"); +const bsp = @import("bsp"); + const FpCamera = extras.FpCamera; const std = @import("std"); const backlog = @import("Backlog"); diff --git a/tools/trenchbroom/FreeImage.dll b/tools/trenchbroom/FreeImage.dll new file mode 100644 index 0000000..1d75e17 Binary files /dev/null and b/tools/trenchbroom/FreeImage.dll differ diff --git a/tools/trenchbroom/Iex-3_1.dll b/tools/trenchbroom/Iex-3_1.dll new file mode 100644 index 0000000..36c7c64 Binary files /dev/null and b/tools/trenchbroom/Iex-3_1.dll differ diff --git a/tools/trenchbroom/IlmThread-3_1.dll b/tools/trenchbroom/IlmThread-3_1.dll new file mode 100644 index 0000000..33f4b4b Binary files /dev/null and b/tools/trenchbroom/IlmThread-3_1.dll differ diff --git a/tools/trenchbroom/Imath-3_1.dll b/tools/trenchbroom/Imath-3_1.dll new file mode 100644 index 0000000..a11bce6 Binary files /dev/null and b/tools/trenchbroom/Imath-3_1.dll differ diff --git a/tools/trenchbroom/OpenEXR-3_1.dll b/tools/trenchbroom/OpenEXR-3_1.dll new file mode 100644 index 0000000..fe83a38 Binary files /dev/null and b/tools/trenchbroom/OpenEXR-3_1.dll differ diff --git a/tools/trenchbroom/Qt5Core.dll b/tools/trenchbroom/Qt5Core.dll new file mode 100644 index 0000000..40e8de1 Binary files /dev/null and b/tools/trenchbroom/Qt5Core.dll differ diff --git a/tools/trenchbroom/Qt5Gui.dll b/tools/trenchbroom/Qt5Gui.dll new file mode 100644 index 0000000..bf38dda Binary files /dev/null and b/tools/trenchbroom/Qt5Gui.dll differ diff --git a/tools/trenchbroom/Qt5Svg.dll b/tools/trenchbroom/Qt5Svg.dll new file mode 100644 index 0000000..edfbf4a Binary files /dev/null and b/tools/trenchbroom/Qt5Svg.dll differ diff --git a/tools/trenchbroom/Qt5Widgets.dll b/tools/trenchbroom/Qt5Widgets.dll new file mode 100644 index 0000000..80ae4e3 Binary files /dev/null and b/tools/trenchbroom/Qt5Widgets.dll differ diff --git a/tools/trenchbroom/TrenchBroom-stripped.pdb b/tools/trenchbroom/TrenchBroom-stripped.pdb new file mode 100644 index 0000000..ec77a5b Binary files /dev/null and b/tools/trenchbroom/TrenchBroom-stripped.pdb differ diff --git a/tools/trenchbroom/TrenchBroom.exe b/tools/trenchbroom/TrenchBroom.exe new file mode 100644 index 0000000..22ce417 Binary files /dev/null and b/tools/trenchbroom/TrenchBroom.exe differ diff --git a/tools/trenchbroom/assimp-vc143-mt.dll b/tools/trenchbroom/assimp-vc143-mt.dll new file mode 100644 index 0000000..c62286b Binary files /dev/null and b/tools/trenchbroom/assimp-vc143-mt.dll differ diff --git a/tools/trenchbroom/brotlicommon.dll b/tools/trenchbroom/brotlicommon.dll new file mode 100644 index 0000000..20fc2e5 Binary files /dev/null and b/tools/trenchbroom/brotlicommon.dll differ diff --git a/tools/trenchbroom/brotlidec.dll b/tools/trenchbroom/brotlidec.dll new file mode 100644 index 0000000..0f15a75 Binary files /dev/null and b/tools/trenchbroom/brotlidec.dll differ diff --git a/tools/trenchbroom/bz2.dll b/tools/trenchbroom/bz2.dll new file mode 100644 index 0000000..156a302 Binary files /dev/null and b/tools/trenchbroom/bz2.dll differ diff --git a/tools/trenchbroom/defaults/assets/textures/__TB_empty.png b/tools/trenchbroom/defaults/assets/textures/__TB_empty.png new file mode 100644 index 0000000..f6aa35c Binary files /dev/null and b/tools/trenchbroom/defaults/assets/textures/__TB_empty.png differ diff --git a/tools/trenchbroom/fmt.dll b/tools/trenchbroom/fmt.dll new file mode 100644 index 0000000..c4b033c Binary files /dev/null and b/tools/trenchbroom/fmt.dll differ diff --git a/tools/trenchbroom/fonts/SIL Open Font License.txt b/tools/trenchbroom/fonts/SIL Open Font License.txt new file mode 100644 index 0000000..295975a --- /dev/null +++ b/tools/trenchbroom/fonts/SIL Open Font License.txt @@ -0,0 +1,43 @@ +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. + +The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the copyright statement(s). + +"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. + +"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. + +5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file diff --git a/tools/trenchbroom/fonts/SourceSansPro-Regular.otf b/tools/trenchbroom/fonts/SourceSansPro-Regular.otf new file mode 100644 index 0000000..38941ae Binary files /dev/null and b/tools/trenchbroom/fonts/SourceSansPro-Regular.otf differ diff --git a/tools/trenchbroom/freetype.dll b/tools/trenchbroom/freetype.dll new file mode 100644 index 0000000..5503ef8 Binary files /dev/null and b/tools/trenchbroom/freetype.dll differ diff --git a/tools/trenchbroom/games/DDayNormandy/GameConfig.cfg b/tools/trenchbroom/games/DDayNormandy/GameConfig.cfg new file mode 100644 index 0000000..ee4b182 --- /dev/null +++ b/tools/trenchbroom/games/DDayNormandy/GameConfig.cfg @@ -0,0 +1,202 @@ +{ + "version": 9, + "name": "D-Day Normandy", + "icon": "Icon.png", + "fileformats": [ + { "format": "Quake2" }, + { "format": "Quake2 (Valve)"} + ], + "filesystem": { + "searchpath": "dday", + "packageformat": { "extension": ".pak", "format": "idpak" } + }, + "materials": { + "root": "textures", + "extensions": [".wal"], + "palette": "pics/colormap.pcx" + }, + "entities": { + "definitions": [ "dday.fgd" ], + "defaultcolor": "0.6 0.6 0.6 1.0" + }, + "tags": { + "brush": [ + { + "name": "Trigger", + "attribs": [ "transparent" ], + "match": "classname", + "pattern": "trigger*", + "material": "trigger" + } + ], + "brushface": [ + { + "name": "Clip", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "clip" + }, + { + "name": "Skip", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "skip" + }, + { + "name": "Hint", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "hint*" + }, + { + "name": "Detail", + "match": "contentflag", + "flags": [ "detail" ] + }, + { + "name": "Liquid", + "match": "contentflag", + "flags": [ "lava", "slime", "water" ] + } + ] + }, + "faceattribs": { + "surfaceflags": [ + { + "name": "light", + "description": "Emit light from the surface, brightness is specified in the 'value' field" + }, + { + "name": "slick", + "description": "The surface is slippery" + }, + { + "name": "sky", + "description": "The surface is sky, the texture will not be drawn, but the background sky box is used instead" + }, + { + "name": "warp", + "description": "The surface warps (like water textures do)" + }, + { + "name": "trans33", + "description": "The surface is 33% transparent" + }, + { + "name": "trans66", + "description": "The surface is 66% transparent" + }, + { + "name": "flowing", + "description": "The texture wraps in a downward 'flowing' pattern (warp must also be set)" + }, + { + "name": "nodraw", + "description": "Used for non-fixed-size brush triggers and clip brushes" + }, + { + "name": "hint", + "description": "Make a primary bsp splitter" + }, + { + "name": "skip", + "description": "Completely ignore, allowing non-closed brushes" + } + ], + "contentflags": [ + { + "name": "solid", + "description": "Default for all brushes" + }, // 1 << 0 + { + "name": "window", + "description": "Brush is a window (not really used)" + }, // 1 << 1 + { + "name": "aux", + "description": "Unused by the engine" + }, // 1 << 2 + { + "name": "lava", + "description": "The brush is lava" + }, // 1 << 3 + { + "name": "slime", + "description": "The brush is slime" + }, // 1 << 4 + { + "name": "water", + "description": "The brush is water" + }, // 1 << 5 + { + "name": "mist", + "description": "The brush is non-solid" + }, // 1 << 6 + { "name": "true" }, // 1 << 7 + { "name": "true" }, // 1 << 8 + { "name": "true" }, // 1 << 9 + { "name": "true" }, // 1 << 10 + { "name": "true" }, // 1 << 11 + { "name": "true" }, // 1 << 12 + { "name": "true" }, // 1 << 13 + { "name": "true" }, // 1 << 14 + { "name": "true" }, // 1 << 15 + { + "name": "playerclip", + "description": "Player cannot pass through the brush (other things can)" + }, // 1 << 16 + { + "name": "mosterclip", + "description": "Monster cannot pass through the brush (player and other things can)" + }, // 1 << 17 + { + "name": "current_0", + "description": "Brush has a current in direction of 0 degrees" + }, // 1 << 18 + { + "name": "current_90", + "description": "Brush has a current in direction of 90 degrees" + }, // 1 << 19 + { + "name": "current_180", + "description": "Brush has a current in direction of 180 degrees" + }, // 1 << 20 + { + "name": "current_270", + "description": "Brush has a current in direction of 270 degrees" + }, // 1 << 21 + { + "name": "current_up", + "description": "Brush has a current in the up direction" + }, // 1 << 22 + { + "name": "current_dn", + "description": "Brush has a current in the down direction" + }, // 1 << 23 + { + "name": "origin", + "description": "Special brush used for specifying origin of rotation for rotating brushes" + }, // 1 << 24 + { + "name": "monster", + "description": "Purpose unknown" + }, // 1 << 25 + { + "name": "corpse", + "description": "Purpose unknown" + }, // 1 << 26 + { + "name": "detail", + "description": "Detail brush" + }, // 1 << 27 + { + "name": "translucent", + "description": "Use for opaque water that does not block vis" + }, // 1 << 28 + { + "name": "ladder", + "description": "Brushes with this flag allow a player to move up and down a vertical surface" + } // 1 << 29 + ] + } +} diff --git a/tools/trenchbroom/games/DDayNormandy/Icon.png b/tools/trenchbroom/games/DDayNormandy/Icon.png new file mode 100644 index 0000000..ebc9799 Binary files /dev/null and b/tools/trenchbroom/games/DDayNormandy/Icon.png differ diff --git a/tools/trenchbroom/games/DDayNormandy/colormap.pcx b/tools/trenchbroom/games/DDayNormandy/colormap.pcx new file mode 100644 index 0000000..857c041 Binary files /dev/null and b/tools/trenchbroom/games/DDayNormandy/colormap.pcx differ diff --git a/tools/trenchbroom/games/DDayNormandy/dday.fgd b/tools/trenchbroom/games/DDayNormandy/dday.fgd new file mode 100644 index 0000000..fbaf030 --- /dev/null +++ b/tools/trenchbroom/games/DDayNormandy/dday.fgd @@ -0,0 +1,636 @@ +// +// D-Day Normandy game definition file (.fgd) +// +// Written by Christian aka Vio +// https://github.com/chow-land +// +// Original dday entity guide: +// https://www.quakewiki.net/archives/dday.planetquake.gamespy.com/site/user_guides/manual/pages/mapmaking.htm +// +// Last updated: July 15th, 2020 +// + +@SolidClass = worldspawn : "World entity" +[ + sky(string) : "Environment map name" + skyaxis(string) : "Vector axis for rotating sky" + skyrotate(string) : "Speed of rotation (degrees/second)" + gravity(integer) : "Gravity" : 800 + message(string) : "Level name" +] +//xaGe: added missing superclasses Appearflags, Targetname, Target and then fixed all the case issues. +@baseclass = Appearflags [ + spawnflags(Flags) = + [ + 256 : "Not in Easy" : 0 + 512 : "Not in Normal" : 0 + 1024 : "Not in Hard" : 0 + 2048 : "Not in Deathmatch" : 0 + ] +] + +@baseclass = Targetname [ targetname(target_source) : "Name" ] +@baseclass = Target [ target(target_destination) : "Target" ] + +@baseclass base(Appearflags, Targetname) size(-16 -16 -24, 16 16 32) color(0 255 0) = PlayerClass [] + +@PointClass = info_team_start : "Configures info for a team. There should be 2 of these on your map." +[ + obj_owner(integer) : "Owning team (0-allies or 10-axis)" + message(string) :"Team Name (required)" + dll(choices) : "Team DLL" = + [ + "usa" : "USA" + "usm" : "US Marines" + "grm" : "Germans" + "gbr" : "British" + "rus" : "Russians" + "jpn" : "Japanese" + "pol" : "Polish" + ] + kills(integer) : "Kills to win" + points(integer) : "Points to win" + nextmap(string) : "Map to load if the team that owns this entity wins (obsolete)" +] + + +// PLAYER SPAWNS + +@PointClass base(PlayerClass) color(127 0 128) = info_player_start : "You wait here when you are dead" [] + +@PointClass base(PlayerClass) color(0 255 0) = info_reinforcements_start : "All players on team will spawn here, unless there is a class-specific spawn for that player's current class. If there are multiple info_reinforcements_start entities for a given team the player will spawn at a random one." +[ + obj_owner(integer) : "Owning Team" : 0 + angle(string) : "Direction the player will face when spawning" : "0 0 0" +] + + +// CLASS-SPECIFIC SPAWNS + +@PointClass base(PlayerClass) color(0 0 255) = info_infantry_start : "Infantry class spawns here" +[ + obj_owner(integer) : "Owning Team" : 0 + angle(string) : "Direction the player will face when spawning" : "0 0 0" +] + +@PointClass base(PlayerClass) color(0 0 255) = info_officer_start : "Officer class spawns here" +[ + obj_owner(integer) : "Owning Team" : 0 + angle(string) : "Direction the player will face when spawning" : "0 0 0" +] + +@PointClass base(PlayerClass) color(0 0 255) = info_lgunner_start : "Light Machinegun class spawns here" +[ + obj_owner(integer) : "Owning Team" : 0 + angle(string) : "Direction the player will face when spawning" : "0 0 0" +] + +@PointClass base(PlayerClass) color(0 0 255) = info_hgunner_start : "Heavy Machinegun class spawns here" +[ + obj_owner(integer) : "Owning Team" : 0 + angle(string) : "Direction the player will face when spawning" : "0 0 0" +] + +@PointClass base(PlayerClass) color(0 0 255) = info_sniper_start : "Sniper class spawns here" +[ + obj_owner(integer) : "Owning Team" : 0 + angle(string) : "Direction the player will face when spawning" : "0 0 0" +] + +@PointClass base(PlayerClass) color(0 0 255) = info_special_start : "Special class spawns here (usually Airborne, but varies for different team dlls" +[ + obj_owner(integer) : "Owning Team" : 0 + angle(string) : "Direction the player will face when spawning" : "0 0 0" +] + +@PointClass base(PlayerClass) color(0 0 255) = info_engineer_start : "Engineer class spawns here" +[ + obj_owner(integer) : "Owning Team" : 0 + angle(string) : "Direction the player will face when spawning" : "0 0 0" +] + +@PointClass base(PlayerClass) color(0 0 255) = info_medic_start : "Medic Class spawns here" +[ + obj_owner(integer) : "Owning Team" : 0 + angle(string) : "Direction the player will face when spawning" : "0 0 0" +] + +@PointClass base(PlayerClass) color(0 0 255) = info_flamethrower_start : "Flamethrower class spawns here" +[ + obj_owner(integer) : "Owning Team" : 0 + angle(string) : "Direction the player will face when spawning" : "0 0 0" +] + + +// MAP PROPS + +@PointClass base(Appearflags, Targetname) color(255 128 0) size(-16 -16 0, 16 16 32) model({ "path": ":models/ships/viper/tris.md2" }) = misc_viper : "The default viper ship entity from Quake2, but replaced with a P51 Mustang." +[ + target(string) : "Direction the P51 model will face" + speed(integer) : "How fast the P51 should fly" + +] +//xaGe: added "path": model to entity so it renders md2s defined by model(string) in TB. +@PointClass base(Appearflags, Targetname) color(255 128 0) size(-16 -16 0, 16 16 32) model({ "path" : model }) = misc_md2 : "General purpose entity for adding an .md2 map model." +[ + model(string) : "Path to the model, example: models/mapmodels/tree/tris.md2" + angle(integer) : "Direction the model will face" +] + + +@PointClass base(Appearflags, Targetname) color(255 128 0) size(-16 -16 0, 16 16 32) model({ "path" : ":models/objects/banner/tris.md2" }) = misc_banner : "German flag 1" +[ + angle(integer) : "Direction the banner will face" +] + +@PointClass base(Appearflags, Targetname) color(255 128 0) size(-16 -16 0, 16 16 32) model({ "path" : ":models/objects/banner1/tris.md2" }) = misc_banner_1 : "German flag 2" +[ + angle(integer) : "Direction the banner will face" +] + +@PointClass base(Appearflags, Targetname) color(255 128 0) size(-16 -16 0, 16 16 32) model({ "path" : ":models/objects/banner2/tris.md2" }) = misc_banner_2 : "German flag 3" +[ + angle(integer) : "Direction the banner will face" +] + +@PointClass base(Appearflags, Targetname) color(255 128 0) size(-16 -16 0, 16 16 32) model({ "path" : ":models/objects/banner3/tris.md2" }) = misc_banner_3 : "British flag" +[ + angle(integer) : "Direction the banner will face" +] + +@PointClass base(Appearflags, Targetname) color(255 128 0) size(-16 -16 0, 16 16 32) model({ "path" : ":models/objects/banner4/tris.md2" }) = misc_banner_4 : "US Flag" +[ + angle(integer) : "Direction the banner will face" +] + +@PointClass base(Appearflags, Targetname) color(255 128 0) size(-16 -16 0, 16 16 32) model({ "path" : ":models/deadbods/dude/tris.md2" }) = misc_skeleton : "A skeleton lying on its back." +[ + angle(integer) : "Direction the skeleton model will face" +] + + +// OBJECTIVES + +@SolidClass base(Appearflags, Targetname, Target) color(0 0 255) = objective_touch : "Player touches this and is awarded points" +[ + obj_owner(integer) : "Assign a value (0, 1, 99); 0=Allies 1=Axis 99=Neutral (Anyone can claim it first)" + message(string) : "Name of the region the entity touches (Center Pill, Right Pill, Donut Room, etc.)" + health(integer) : "Enter a number value representing the number of points to be awarded to the other team when the entity is claimed" + dmg(integer) : "Enter a number value representing the number of points to be deducted when the entity owner loses the objective" +] + + +@SolidClass base(Appearflags, Targetname, Target) color(0 0 255) = func_explosive_objective : "Gives points when blown up" +[ + obj_owner(integer) : "Assign a value (0, 1, 99); 0=Allies 1=Axis 99=Neutral (Anyone can claim it first)" + obj_name(string) : "Name of the object to be displayed when destroyed" + obj_loss(integer) : "Amount of points taken away from the owner when destroyed" + obj_gain(integer) : "Amount of points given to the team that doesn’t own the objective when it is destroyed" + message(string) : "Name of the region the entity touches (Center Pill, Right Pill, Donut Room, etc.)" + health(integer) : " Amount of damage it takes to blow the objective up" + dmg(integer) : "Radius damage to inflict on people surrounding the objective when it explodes" +] + + +// The quake2 turret entities can be used in dday to create Player-usable turrets. +// The process for creating turrets is the same as in regular quake2, with the addition of a new entity, "turret_range", which defines the area where the player must occupy to use the turret. To use a turret you need to switch to fists and then right click. +// More info: http://ddaydev.com/forum/viewtopic.php?f=2&t=235 + + +@SolidClass base (Appearflags, Targetname, Target) color (128 0 128) = turret_range : "Turret Range. Use this to define the area the player must occupy to use the turret." +[ + team(string) : "Team" +] + +@SolidClass base(Appearflags, Targetname, Target) color(128 255 128) = turret_breach : "Turret breach" +[ + // These first 6 values are dday specific. + rate(integer) : "firing rate, set to 0 for machineguns or higher for tanks" + count(integer) : "number of rounds, -1 is infinite" + ammo_type(string) : "shell, fire, bullet, tracer, rocket, or grenade" + fire_sound(string) : "the .wav file you want to play for firing" + ammo_speed(integer) : "how fast the ammo goes through the air" + model(string) : "if you want to use an md2 for the gun instead of bsp brushes in the map" + + speed(integer) : "Speed" : 50 + dmg(integer) : "Damage" : 10 + minpitch(integer) : "Miminum pitch angle" : -30 + maxpitch(integer) : "Maximum pitch angle" : 30 + minyaw(integer) : "Minimum yaw angle" : 0 + maxyaw(integer) : "Maximum yaw angle" : 360 + team(string) : "Team" + _minlight(string) : "Minimum light (optional)" +] +@SolidClass base(Appearflags) color(128 255 128) = turret_base : "Turret base" +[ + team(string) : "Team" + _minlight(string) : "Minimum light (optional)" +] + + +// Vanilla Q2 Entities Supported by D-Day + + +// Keep in mind when using func_areaportal that it must +// *completely* separate two areas. otherwise, you will +// get an error message and the areaportal will not work +// +// 0221 - is there any point in a "style" key? +@SolidClass base(Appearflags, Targetname) = func_areaportal : "Area portal (Vis blocker)" [] + +// 0221 - added "pathtarget" +// 0221 - changed "sounds" information +@SolidClass base(Appearflags, Target, Targetname) color(0 128 204) = func_button : "Button" +[ + pathtarget(string) : "Elevator level target" + speed(integer) : "Speed" : 40 + wait(choices) : "Wait before reset" : 1 = + [ + -1 : "Never Return" + ] + lip(integer) : "Lip remaining after move" : 4 + health(integer) : "Health (shootable)" + sounds(choices) : "Sounds" : 0 = + [ + 0 : "Audible" + 1 : "Silent" + ] +// sounds(choices) : "Sounds" : 2 = +// [ +// 1 : "Silent" +// 2 : "Steam Metal" +// 3 : "Wodden Clunk" +// 4 : "Metallic Click" +// 5 : "In-Out" +// ] + message(string) : "Activation message" + _minlight(integer) : "Minimum light (optional)" +] + + + + +// 0221 - updated "sounds" information +// 0221 - added "killtarget" +@SolidClass base(Appearflags, Targetname, Target) color(0 128 204) = func_door : "Door" +[ + spawnflags(Flags) = + [ + 1 : "Start Open" : 0 + 4 : "Crusher" : 0 + 8 : "No Monsters" : 0 + 16 : "Animated" : 0 + 32 : "Toggle" : 0 + 64 : "Animated Fast" : 0 + ] + killtarget(string) : "Kill Target" + team(string) : "Team" + message(string) : "Trigger message" + health(integer) : "Health (shootable)" + speed(integer) : "Speed" : 100 + wait(choices) : "Wait before close" : 3 = + [ + -1 : "Stay open" + ] + lip(integer) : "Lip remaining after move" : 8 + dmg(integer) : "Damage when blocked" : 2 + sounds(choices) : "Sounds" : 0 = + [ + 0 : "Audible" + 1 : "Silent" + ] +// sounds(choices) : "Sounds" : 3 = +// [ +// 1 : "Silent" +// 2 : "Light" +// 3 : "Medium" +// 4 : "Heavy" +// ] + _minlight(integer) : "Minimum light (optional)" +] + +// 0221 - added "killtarget" and "target" keys +// 0221 - updated "sounds" info +// 0221 - removed "lip" key +@SolidClass base(Appearflags, Targetname, Target) color(0 128 204) = func_door_rotating : "Rotating Door" +[ + spawnflags(Flags) = + [ + 1 : "Start Open" : 0 + 2 : "Reverse" : 0 + 4 : "Crusher" : 0 + 8 : "No Monsters" : 0 + 16 : "Animated" : 0 + 32 : "Toggle" : 0 + 64 : "X Axis" : 0 + 128 : "Y Axis" : 0 + ] + killtarget(string) : "Kill Target" + team(string) : "Team" + distance(integer) : "Degrees of rotation" : 90 + message(string) : "Trigger message" + health(integer) : "Health (shootable)" + speed(integer) : "Speed" : 100 + wait(choices) : "Wait before close" : 3 = + [ + -1 : "Stay open" + ] + dmg(integer) : "Damage when blocked" : 2 + sounds(choices) : "Sounds" : 0 = + [ + 0 : "Audible" + 1 : "Silent" + ] +// sounds(choices) : "Sounds" : 3 = +// [ +// 1 : "Silent" +// 2 : "Light" +// 3 : "Medium" +// 4 : "Heavy" +// ] + _minlight(integer) : "Minimum light (optional)" +] + + +// not visible in DM mode +// +// 0221 - added "_minlight" key (even tho you dont want it to stand out) +@SolidClass base(Appearflags, Targetname, Target) color(0 128 204) = func_explosive : "Exploding/Breakable brush" +[ + spawnflags(Flags) = + [ + 1 : "Trigger Spawn" : 0 + 2 : "Animated" : 0 + 4 : "Animated Fast" : 0 + ] + health(integer) : "Health" : 100 + mass(integer) : "Mass (debris)" : 75 + dmg(integer) : "Damage" : 0 + _minlight(integer) : "Minimum light (optional)" +] + +@SolidClass base(Appearflags, Targetname) color(255 0 0) = func_killbox : "Instant death" [] + +// 0221 - added "_minlight" key +@SolidClass base(Appearflags, Targetname) color (0 128 204) = func_object : "Solid bmodel, will fall if its support is removed" +[ + spawnflags(Flags) = + [ + 1 : "Trigger Spawn" : 0 + 2 : "Animated" : 0 + 4 : "Animated Fast" : 0 + ] + _minlight(integer) : "Minimum light (optional)" +] + +// 0221 - removed "sounds" key +@SolidClass base(Appearflags, Targetname) color(0 128 204) = func_plat : "Platform" +[ + spawnflags(Flags) = + [ + 1 : "Plat Low Trigger" : 0 + ] + speed(integer) : "Speed" : 100 + accel(integer) : "Acceleration" : 500 + lip(integer) : "Lip remaining after move" : 8 + height(integer) : "Movement distance" + _minlight(integer) : "Minimum light (optional)" +] + +// 0222 - added "team" key +@SolidClass base(Appearflags, Targetname) color(0 128 204) = func_rotating : "Rotating brush" +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + 2 : "Reverse" : 0 + 4 : "X Axis" : 0 + 8 : "Y Axis" : 0 + 16 : "Pain on Touch" : 0 + 32 : "Block Stops" : 0 + 64 : "Animated" : 0 + 128 : "Animated Fast" : 0 + ] + team(string) : "Team" + speed(integer) : "Speed" : 100 + dmg(integer) : "Damage when blocked" : 2 + _minlight(integer) : "Minimum light (optional)" +] + +@PointClass base(Appearflags, Targetname, Target) color(76 25 153) size(-8 -8 -8, 8 8 8) = func_timer : "Timer" +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + ] + wait(integer) : "Base wait time" : 1 + random(integer) : "Wait variance (+/-)" + delay(integer) : "Delay before first firing" + pausetime(integer) : "Additional delay" +] + +// 0219 - added "team" key +@SolidClass base(Appearflags, Targetname) color(0 128 204) = func_train : "Moving platform" +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + 2 : "Toggle" : 0 + 4 : "Block Stops" : 0 + ] + target(string) : "First stop target" + team(string) : "Team" + speed(integer) : "Speed" : 100 + dmg(integer) : "Damage when blocked" : 2 + noise(string) : "Sound (path/file.wav)" + _minlight(integer) : "Minimum light (optional)" +] + +// 0221 - added a "_minlight" key +@SolidClass base(Appearflags, Targetname) color(0 128 204) = func_wall : "Solid Wall" +[ + spawnflags(Flags) = + [ + 1 : "Trigger Spawn" : 0 + 2 : "Toggle" : 0 + 4 : "Start On" : 0 + 8 : "Animated" : 0 + 16 : "Animated Fast" : 0 + ] + _minlight(integer) : "Minimum light (optional)" +] + +@PointClass base(Appearflags, Targetname) color(0 128 0) size(-4 -4 -4, 4 4 4) = info_null : "Spotlight target" [] +@PointClass base(info_null) = info_notnull : "Lightning target" [] + + +@PointClass base(Appearflags, Target, Targetname) color(0 255 0) size(-8 -8 -8, 8 8 8) = light : "Light" +[ + spawnflags(Flags) = + [ + 1 : "Start Off" : 0 + ] + light(integer) : "Brightness" : 300 + style(Choices) : "Style" : 0 = + [ + 0 : "Normal" + 1 : "Flicker #1" + 6 : "Flicker #2" + 2 : "Slow Strong Pulse" + 3 : "Candle #1" + 7 : "Candle #2" + 8 : "Candle #3" + 4 : "Fast Strobe" + 5 : "Gentle Pulse #1" + 9 : "Slow Strobe" + 10 : "Fluorescent Flicker" + 11 : "Slow pulse, no black" + ] + _cone(integer) : "Size of light (spotlight)" : 10 +] + +// actor code is still broken...leaving this in because i know *someone* will fix +// this because its pretty damn cool. +@PointClass base(PlayerClass, Target) = misc_actor : "Actor" +[ + health(integer) : "Health" : 100 +] + +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-32 -32 -24, 32 32 -16) model({ "path": ":models/objects/dmspot/tris.md2", "skin": 1 }) = misc_teleporter : "Teleporter: To hide the teleport pads, place them units 10 units into a brush." [ target(string) : "Teleport Destination" ] +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-32 -32 -24, 32 32 -16) model({ "path": ":models/objects/dmspot/tris.md2", "skin": 0 }) = misc_teleporter_dest : "Teleport Destination: To hide the teleport pads, place them units 10 units into a brush." [] + + +// using a "wait" value of -1 on a path corner causes a func_train to go silent between +// itself and the next path corner when the train is restarted. The train's sound will +// resume as soon as it reaches a path corner with a "wait" value other than -1 +@PointClass base(Appearflags, Targetname) color(128 76 0) size(-8 -8 -8, 8 8 8) = path_corner : "Path marker" +[ + spawnflags(Flags) = + [ + 1 : "Teleport" : 0 + ] + target(string) : "Next path target" + pathtarget(string) : "Event to trigger" + wait(choices) : "Wait" : 0 = + [ + -1 : "Wait for retrigger" + ] +] + +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_explosion : "Explosion" +[ + delay(integer) : "Delay before explosion" + dmg(integer) : "Radius damage" : 0 +] + +// looped sounds are automatically volume 1, attenuation 3 :\ +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_speaker : "Sound player" +[ + spawnflags(Flags) = + [ + 1 : "Looped On" : 0 + 2 : "Looped Off" : 0 + 4 : "Reliable" : 0 + ] + noise(string) : "Sound (path/file.wav)" + attenuation(Choices) : "Attenuation" : 1 = + [ + -1 : "None, send to whole level" + 1 : "Normal fighting sounds" + 2 : "Idle sound level" + 3 : "Ambient sound level" + ] + volume(integer) : "Volume (0.0 - 1.0)" : 1 +] + +// "sounds" values other than 1 are silent. leaving in the other +// options for availability to mods/fixes +// +// 0221 - clarified "count" description +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_splash : "Creates a splash when used" +[ + sounds(choices) : "Type of splash" : 2 = + [ + 1 : "Sparks" + 2 : "Blue water" + 3 : "Brown water" + 4 : "Slime" + 5 : "Lava" + 6 : "Blood" + ] + count(integer) : "Number of pixels in splash (1 - 255)" + dmg(integer) : "Radius damage" +] + + +// 0221 - added "delay" and "killtarget" keys +@PointClass base(Appearflags, Target) color(128 128 128) size(-8 -8 -8, 8 8 8) = trigger_always : "Always triggers" +[ + killtarget(string) : "Kill Target" + delay(integer) : "Time before triggering" +] + +@SolidClass base(Appearflags, Targetname, Target) color(128 128 128) = trigger_counter : "Counter" +[ + spawnflags(Flags) = + [ + 1 : "No Message" : 0 + ] + count(integer) : "Count before trigger" : 2 +] + +@PointClass base(Appearflags, Targetname, Target) color(76 25 153) = trigger_elevator : "Elevator trigger" [] + +@SolidClass base(Appearflags) color(128 128 128) = trigger_gravity : "Change gravity" +[ + gravity(integer) : "Gravity (standard = 1.0)" : 1 +] + +@SolidClass base(Appearflags, Targetname) color(128 128 128) = trigger_hurt : "Hurts on touch" +[ + spawnflags(Flags) = + [ + 1 : "Start Off" : 0 + 2 : "Toggle" : 0 + 4 : "Silent" : 0 + 8 : "No Protection" : 0 + 16 : "Slow hurt" : 0 + ] + dmg(integer) : "Damage" : 5 +] + +// 0221 - switched around _relay, _once, and _multiple +@PointClass base(Appearflags, Targetname, Target) color(128 128 128) = trigger_relay : "Relay trigger" +[ + killtarget(string) : "Kill Target" + delay(integer) : "Time before triggering" + message(string) : "Trigger message" +] + +// 0303 - removed "sounds" key +@SolidClass base(trigger_relay) = trigger_once : "Single fire trigger" +[ + spawnflags(Flags) = + [ + 4 : "Triggered" : 0 + ] +] + +@SolidClass base(trigger_once) = trigger_multiple : "Multiple fire trigger" +[ + spawnflags(Flags) = + [ + 1 : "Monster" : 0 + 2 : "Not Player" : 0 + ] + wait(integer) : "Seconds between triggers" : 0 +] + +@SolidClass base(Appearflags) color(128 128 128) = trigger_push : "Push trigger" +[ + spawnflags(Flags) = + [ + 1 : "Push Once" : 0 + ] + speed(integer) : "Speed of push" : 1000 +] \ No newline at end of file diff --git a/tools/trenchbroom/games/Daikatana/Common.fgd b/tools/trenchbroom/games/Daikatana/Common.fgd new file mode 100644 index 0000000..73618cf --- /dev/null +++ b/tools/trenchbroom/games/Daikatana/Common.fgd @@ -0,0 +1,1566 @@ +// +// Daikatana game definition file (.fgd) +// Common entities +// for Trenchbroom +// last update: 6 Oct, 2018 +// version: 1 +// +// written by Dekonega / dekonega(at)windowslive.com +// email me with improvements and suggestions +// + + +// +// worldspawn +// +@SolidClass = worldspawn : "Only used for the world entity" +[ + cinematic_intro(string) : "cinematic scene played when map loads" + loadscreen(string) : "loading screen" + palette(string) : "texture palette used" + ambient(integer) : "ambient light" + fog_value(integer) : "fog on-off/intensity" + fog_color(color255) : "rgb color of fog" + fog_start(integer) : "start of fog volume" + fog_end(integer) : "end of fog volume" + _color(color255) : "environmental color" + episode(choices) : "number of episode" : 1 = + [ + 1 : "Episode 1" + 2 : "Episode 2" + 3 : "Episode 3" + 4 : "Episode 4" + ] + mapname(string) : "name of the map" + musictrack(string) : "name of MP3 track to play when level starts" + sky(string) : "skybox name" + cloudname(string) : "name of cloud texture to use, no suffix" + cloudxdir(float) : "cloud x scroll value (-1 to 1, default 1.0)" + cloudydir(float) : "cloud y scroll value (-1 to 1, default 0.8)" + cloud1tile(integer) : "number of repeats of layer 1 cloud texture (default 8)" + cloud2tile(integer) : "number of repeats of layer 2 cloud texture (default 2)" + cloud1speed(integer) : "scrolling speed for layer 1 (default 1)" + cloud2speed(integer) : "scrolling speed for layer 2 (default 4)" + cloud2alpha(float) : "translucency of layer 2 (default 0.7, 0 means no layer 2)" + lightningfreq(float) : "min seconds between lightning flashes (default 0.25, 0 means no lightning)" +] + + +// +// Common properties +// +@BaseClass = Target +[ + target(target_destination) : "Target" +] + +@BaseClass = Targetname +[ + targetname(target_source) : "Name" +] + +@BaseClass = Sidekickflags +[ + spawnflags(Flags) = + [ + 1 : "Superfly" : 0 + 2 : "Mikiko" : 0 + ] +] + +@BaseClass = Appearflags +[ + spawnflags(Flags) = + [ + 4096 : "Not in Easy (Ronin)" : 0 + 8192 : "Not in Normal (Samurai)" : 0 + 16384 : "Not in Hard (Shogun)" : 0 + 32768 : "Not in Deathmatch" : 0 + ] +] + +@BaseClass = DecorationFlags +[ + spawnflags(Flags) = + [ + 1: "DECO_EXPLODE" : 0 + 2: "NO_EXPLODE_NO_BREAK" : 0 + 4: "DECO_PUSHABLE" : 0 + 8: "WOOD_DEBRIS" : 0 + 16: "METAL_DEBRIS" : 0 + 32: "GLASS_DEBRIS" : 0 + 64: "GIB_DEBRIS" : 0 + 128: "ROTATE" : 0 + 256: "DECO_TRANSLUCENT" : 0 + ] +] + +@BaseClass = PurifierShard +[ + spawnflags(Flags) = + [ + 1: "x" : 0 + 2: "x" : 0 + 4: "USE_TARGETS" : 0 + ] +] + +@BaseClass = AntidoteFlags +[ + spawnflags(Flags) = + [ + 1: "x" : 0 + 2: "x" : 0 + 4: "USE_TARGETS" : 0 + ] +] + +@BaseClass = KeyFlags +[ + spawnflags(Flags) = + [ + 1: "USE_ONCE" : 0 + 2: "UNLOCK" : 0 + 4: "USE_TARGETS" : 0 + ] + + sound(string): "sound played when the key is used" +] + +@BaseClass base(Appearflags, Target, Sidekickflags) color(0 0.5 0.8) size(-16 -16 0, 16 16 32) = Ammo +[ + team(string) : "Team" +] + +@BaseClass color(0.5 0.5 0) size(-8 -8 -8, 8 8 8) = Animal +[ + spawnflags(Flags) = + [ + 1: "WANDER" : 0 + 2: "PATHFOLLOW" : 0 + ] +] + +@BaseClass base(Appearflags, Target, Sidekickflags) color(0 0.5 0.8) size(-20 -20 0, 20 20 32) = Weapons +[ + team(string) : "Team" +] + +@BaseClass base(Appearflags, Target, Targetname) = MonsterFlags +[ + spawnflags(Flags) = + [ + 1 : "WANDER" : 0 + 2 : "PATHFOLLOW" : 0 + 4 : "NODE_WANDER" : 0 + 8 : "RANDOM_WANDER" : 0 + 16 : "IGNORE_PLAYER" : 0 + 32 : "SNIPE" : 0 + 64 : "DO_NOT_FLY" : 0 + 128 : "DO_NOT_MOVE" : 0 + 256 : "x" : 0 + 512 : "TAKE_COVER" : 0 + 1024 : "ALWAYS_GIB" : 0 + ] + + spawnname(string): "classname of entity to throw out upon death." + sight(integer): "Range that the monster can see the player and will react." + speak(integer): "Range that the monster can speak to other monsters so they can help out." +] + + +// +// Debugging +// +@PointClass base(Appearflags) color(0 0.5 0.8) size(-16 -16 -24, 16 16 32) = viewthing : "For debugging level - dont use" [] +@PointClass base(Appearflags) color(1 0.5 0) size(-16 -16 -16, 16 16 16) = view_rotate : "For debugging level - dont use" [] + + +// +// Lights +// +@BaseClass = LightStyleFX +[ + style(choices) : "Number of style to use, between 0-63" : 0 = + [ + 0: "Normal" + 1: "Flicker #1" + 6: "Flicker #2" + 2: "Slow Strong Pulse" + 3: "Candle #1" + 7: "Candle #2" + 8: "Candle #3" + 4: "Fast Strobe" + 5: "Gentle Pulse #1" + 9: "Slow Strobe" + 10: "Fluorescent Flicker" + 11: "Slow pulse, no black" + 12: "12 - 63 Custom" + ] +] + +@PointClass base(Appearflags, LightStyleFX, Target, Targetname) color(0 1 0) size(-8 -8 -8, 8 8 8) = light : "Light" +[ + spawnflags(Flags) = + [ + 1 : "Start Off" : 0 + 2 : "Flare" : 0 + ] + + light(integer) : "Intensity of light" : 300 + _cone(integer) : "Size of light (spotlight) default: 10" + lightstyle(string) : "String to define lightstyle" +] + +@PointClass base(Appearflags) color(0.9 0.9 0.9) size(-8 -8 -8, 8 8 8) = light_flare : "Light (Flare)" +[ + spawnflags(Flags) = + [ + 1 : "Start Off" : 0 + ] + + model(string) : "Sprite model name" + scale(float) : "Sprite model scale" : 1.0 +] + +@PointClass base(Appearflags, LightStyleFX) color(0 1 0) size(-8 -8 -8, 8 8 8) = light_walltorch : "Light (Walltorch)" +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + ] + + lightstyle(string) : "string to define lightstyle" +] + +@BaseClass base(Appearflags) color(0 1 0) size(-8 -8 -28, 8 8 8) = EpisodeLight [] + +@PointClass base(EpisodeLight) = light_e1 : "Light (Episode 1)" +[ + scale(string) : "Amount to scale (%f %f %f)" +] + +@PointClass base(EpisodeLight) = light_e2 : "Light (Episode 2)" +[ + spawnflags(Flags) = + [ + 1 : "D2_TORCH1" : 0 + 2 : "D2_TORCH1B" : 0 + 4 : "D2_TORCH2" : 0 + 8 : "D2_TORCH3" : 0 + ] + + scale(string) : "Amount to scale (%f %f %f)" +] + +@PointClass base(EpisodeLight) = light_e3 : "Light (Episode 3)" +[ + spawnflags(Flags) = + [ + 1 : "D3_FIRESHELF" : 0 + 2 : "D3_CANDLE" : 0 + 4 : "D3_FLAMHOLD" : 0 + ] + + scale(string) : "Amount to scale (%f %f %f)" +] + +@PointClass base(EpisodeLight) = light_e4 : "Light (Episode 4)" +[ + spawnflags(Flags) = + [ + 1 : "D4_BARREL1" : 0 + ] + + scale(string) : "Amount to scale (%f %f %f)" +] + +@PointClass base(Appearflags, LightStyleFX) color(0 1 0) size(-8 -8 -8, 8 8 8) = light_strobe : "Light (Strobe)" +[ + spawnflags(Flags) = + [ + 1 : "START_ON" : 0 + ] + + lightstyle(string) : "string to define lightstyle" +] + + +// +// Effects +// +@SolidClass base(Appearflags) color(0 1 0) = effect_fog : "Fog Effect - Duh, fog." [] + +@SolidClass base(Appearflags) color(1 1 1) = effect_snow : "Snow Effect" +[ + spawnflags(Flags) = + [ + 1 : "FALL_STRAIGHT" : 0 + ] + + height(integer) : "distance the snow/rain is supposed to fall" +] + +@SolidClass base(Appearflags) color(0 0.5 0.8) = effect_rain : "Rain Effect" +[ + spawnflags(Flags) = + [ + 1 : "NORTH" : 0 + 2 : "SOUTH" : 0 + 4 : "EAST" : 0 + 8 : "WEST" : 0 + ] + + height(integer) : "distance the snow/rain is supposed to fall" +] + +@PointClass base(Appearflags, Target, Targetname) color(1 1 1) size(-8 -8 -8, 8 8 8) = effect_lightning : "Lightning Effect" +[ + spawnflags(Flags) = + [ + 1 : "START_ON" : 0 + 2 : "CYCLE" : 0 + 4 : "GROUND_STRIKES" : 0 + 8 : "RANDOM_DELAY" : 0 + 16 : "SPAWN_LIGHT" : 0 + 32 : "NO_CLIENTS" : 0 + 64 : "TRACE_DMG" : 0 + 128 : "STRIKE_ONCE" : 0 + 256 : "NO_SPARKS" : 0 + 512 : "CONSTANT" : 0 + 1024 : "SCORCH" : 0 + ] + + delay(float) : "time between strikes (default 2.0)" : 2.0 + dmg(float) : "damage if a PLAYER gets hit (default 0.0) based on duration (default 0.5 1 defined)" + sound1(string) : "wave file to play when lightning strikes (random if > 1 defined)" + sound2(string) : "wave file to play when lightning strikes (random if > 1 defined)" + sound3(string) : "wave file to play when lightning strikes (random if > 1 defined)" +] + +@SolidClass base(Appearflags) color(1 0.6 0.3) = effect_steam : "Steam Effect" +[ + spawnflags(flags) = + [ + 1 : "RANDOM_DELAY" : 0 + 2 : "START_ON" : 0 + 4 : "JET_ONCE" : 0 + 8 : "FREEZE_SPRAY" : 0 + ] + + delay(float) : "time between jets (default 6.0)" : 6.0 + duration(float) : "length of time to spray (default 2.0)" : 2.0 + vector(vector) : "direction/distance to jet steam" + damage(float) : "damage if a PLAYER gets hit (default 0.0)" : 0.0 + scale(float) : "set the scale of the steam sprite (default 1.0)" : 1.0 + sound(string) : "sound played while steam is jetting" +] + + +// +// Specialised Effects +// +@PointClass base(Appearflags, Target, Targetname) color(.65 0.65 0.15) size(-8 -8 -8, 8 8 8) = sfx_complex_particle : "Complex Particle Effect" +[ + spawnflags(flags) = + [ + 1 : "P_SIMPLE" : 0 + 2 : "P_TRIANGLE" : 0 + 4 : "P_RAIN" : 0 + 8 : "P_SMOKE" : 0 + 16 : "P_FLARE" : 0 + 32 : "P_DEBRIS" : 0 + 64 : "P_SOFTROUND" : 0 + 128 : "P_BUBBLE" : 0 + 256 : "TOGGLE_EMIT" : 0 + 512 : "RANDOM_EMIT" : 0 + 1024 : "START_OFF" : 0 + 2048 : "TOGGLE" : 0 + ] + + count(integer): "Number of particles to spray" : 1 + spread(integer): "Degrees of Conic spread for the particle stream (360 = a sphere)" : 1 + velocity(float): "How fast the particles move" + emission(integer): "Emission rate on a per frame basis (!<1 anything <1 will = 1)" + emissiontime(integer): "Amount of frames particle Emission occurs" + scale(float): "The size of the particles (!< 0.01f !>200.0f)" + delta_alpha(float): "The decay rate of the particle's life time" + alpha_level(float): "The initial state of the Alpha level" + gravity(float): "How much gravity to apply to particles." : 0 + gravitydir(string): "Name of target that gravity will be applied towards." : "down" + stoptime(integer): "Time for the SFX Particle generator to spit out particles before it completely shuts down" + radius(integer): "Radius spread for spawning particles" + _color(color255): "Particle color" +] + + +// +// Misc +// +@BaseClass base(Appearflags, Target, Targetname) color(1 0 0) size(-16 -16 -24, 16 16 32) = HealthStations [] + +@PointClass base(HealthStations) = misc_hosportal : "Hosportal" +[ + spawnflags(flags) = + [ + 1 : "ALLOW_HEALTH" : 0 + ] + + style(choices): "Hosportal style" : 1 = + [ + 0 : "large (with walls)" + 1 : "medium (no walls)" + 2 : "small (monitor)" + ] + + health(integer): "health of entity (0 if indestructable)" + max_juice(integer): "max amount of health to restore before depleted (100)" +] + +@PointClass base(HealthStations) = misc_fountain : "Greek health fountain." [] + +@PointClass base(HealthStations) = misc_drugbox : "Crate of drugs. Restores health." [] + +@PointClass base(HealthStations) = misc_healthtree : "Healing fruit tree." +[ + max_fruit(choices): "max # of fruits on tree (5)" : 5 = + [ + 1: "1 fruit" + 2: "2 fruits" + 3: "3 fruits" + 4: "4 fruits" + 5: "5 fruits" + + ] + + recharge_rate(integer): "recharge time (seconds) for tree" +] + +@PointClass base(Appearflags) color(1 0.5 0) size(-8 -8 -8, 8 8 8) = misc_lavaball_drop : "Lavaball drop" [] + +@PointClass base(Appearflags, Target) color(1 0.5 0) size(-8 -8 -8, 8 8 8) = misc_lavaball_toss : "Lavaball toss" +[ + // target(string) : "can be triggered" + mintime(float) : "minimum time between tosses (default = 4.0 seconds)" : 4.0 + maxtime(float) : "maximum time between tosses (default = 12.0 seconds)" : 12.0 + damage(integer) : "damage to do when an hitting something" + upmin(integer) : "minimum upward velocity (default = 200)" : 200 + upmax(integer) : "maximum upward velocity (default = 800)" : 800 +] + + +// +// Functions +// +@SolidClass base(Appearflags, Targetname) color(0 0.5 0.8) = func_areaportal : "Area portal" [] + +@SolidClass base(Appearflags) color(0 0.5 0.8) = func_group : "Group" [] + +@PointClass base(Appearflags, Target, Targetname) color(0 0.5 0.8) size(-4 -4 -4, 4 4 4) = func_gib : "Gib Generator" +[ + spawnflags(Flags) = + [ + 1: "GIB_ROBOTIC" : 0 + 2: "GIB_BONE" : 0 + 4: "NO_BLOOD" : 0 + 8: "START_ON" : 0 + 16: "NO_TOGGLE" : 0 + ] + COUNT(integer): "Number of gibs to throw out per think cycle" + SPREAD(integer): "Degrees of Conic spread for the particle stream" + VELOCITY(float): "How fast the gibs move" + SCALE(float): "The size of the gibs" + STOPTIME(integer): "Time for the gib generator to spit out gibs before it toggles itself off." + MIN(integer): "Min range for sound." + MAX(integer): "Max range for sound." + VOLUME(float): "Volume for sound." +] + +@SolidClass base(Appearflags, Target, Targetname) color(0 0.5 0.8) = func_door : "Door" +[ + spawnflags(Flags) = + [ + 1: "START_OPEN" : 0 + 2: "REVERSE" : 0 + 4: "DOOR_DONT_LINK" : 0 + 8: "TOGGLE" : 0 + 16: "AUTO_OPEN" : 0 + 32: "USE_TO_CLOSE" : 0 + 64: "CONTINUOUS" : 0 + 128: "LOOP_DOOR_SOUNDS" : 0 + 256: "STRUGGLE" : 0 + 512: "FORCEMOVE" : 0 + ] + + message(string): "printed when the door is touched" + angle(integer): "determines the opening direction" + keyname(string): "if set, the player must have the specified item in their inventory" + health(integer): "if set, door must be shot open" + speed(integer): "movement speed" : 100 + wait(integer): "time to wait before returning" : 3 + lip(integer): "amount of door visible remaining at end of move" : 8 + dmg(integer): "damage to inflict when blocked" : 2 + sound_opening(string): "name of the sound to play during opening, ie. doors/creek.wav" + sound_open_finish(string): "name of the sound to play when opening completes, ie. doors/slam.wav" + sound_closing(string): "name of the sound to play when closing starts, ie. doors/creek.wav" + sound_close_finish(string): "name of the sound to play when closing completes, ie. doors/slam.wav" + cinescript(string): "name of the cinematic script to run" + aiscript(string): "name of the AI script to run" +] + +@SolidClass base(Appearflags, Targetname) color(0 0.5 0.8) = func_plat : "Platform" +[ + spawnflags(Flags) = + [ + 1 : "PLAT_START_UP" : 0 + 2 : "X" : 0 + 4 : "X" : 0 + 8 : "PLAT_TOGGLE" : 0 + ] + + message(string): "printed when the door is touched if it is a trigger door and it hasn't been fired yet" + angle(integer): "determines the opening direction" + health(integer): "if set, door must be shot open" + speed(integer): "movement speed (100 default)" : 100 + wait(integer): "time to wait before returning (3 default, -1 = never return)" : 3 + height(integer): "number of units to move the platform up from spawn position. If height is not specified, then the movement distance is determined based on the vertical size of the platform." + dmg(integer): "damage to inflict when blocked (2 default)" : 2 + sound_up(string): "name of the sound to play when going up, ie. doors/creek.wav" + sound_top(string): "name of the sound to play when plat hits top, ie. doors/slam.wav" + sound_down(string): "name of the sound to play when going down, ie. doors/creek.wav" + sound_bottom(string): "name of the sound to play when plat hits bottom, ie. doors/slam.wav" + volume(float): "0.0 to 1.0" + min(integer): "0 to 2040 - minimum distance (volume full)" + max(integer): "0 to 8160 - maximum distance (volume none)" +] + +@SolidClass base(Appearflags, Targetname) color(0 0.5 0.8) = func_door_rotate : "Rotating door" +[ + spawnflags(Flags) = + [ + 1: "START_OPEN" : 0 + 2: "REVERSE" : 0 + 4: "DOOR_DONT_LINK" : 0 + 8: "TOGGLE" : 0 + 16: "AUTO_OPEN" : 0 + 32: "USE_TO_CLOSE" : 0 + 64: "CONTINUOUS" : 0 + 128: "X_AXIS" : 0 + 256: "Y_AXIS" : 0 + 512: "SWING" : 0 + 1024: "STRUGGLE" : 0 + 2048: "ROTATE_LOOP_SOUNDS" : 0 + ] + + distance(integer): "is how many degrees the door will be rotated." + speed(integer): "determines how fast the door moves; default value is 100." : 100 + message(string): "is printed when the door is touched if it is a trigger door and it hasn't been fired yet." + health(integer): "if set, door must be shot open" + wait(integer): "wait before returning (3 default, -1 = never return)" : 3 + damage(integer): "damage to inflict when blocked (2 default)" : 2 + sound_opening(string): "name of the sound to play during opening, ie. doors/creek.wav" + sound_open_finish(string): "name of the sound to play when opening completes, ie. doors/slam.wav" + sound_closing(string): "name of the sound to play when closing starts, ie. doors/creek.wav" + sound_close_finish(string): "name of the sound to play when closing completes, ie. doors/slam.wav" + volume(float): "0.0 to 1.0" + min(integer): "0 to 2040 - minimum distance (volume full)" + max(integer): "0 to 8160 - maximum distance (volume none)" + boing(integer): "0 = ignore (default), 1 = simulate bouncing physics" : 0 + accelerate(integer): "0 = ignore (default), 1 = accelerate rotation from 0 to speed" : 0 + mass(integer): "0 = ignore (default), valid range is 1 = mass of player to 10. NOTE: dust and spawnquake are generated based on mass." : 0 + dust(integer): "0 = ignore (default), 1 = create a dust cloud when the brush stops" : 0 + spawnquake(integer): "0 = ignore (default), 1 = spawn a small quake when the brush stops" : 0 +] + +@SolidClass base(Appearflags, Target, Targetname) color(0 0.5 0.8) = func_rotate : "Rotate" +[ + spawnflags(Flags) = + [ + 1: "START_ON" : 0 + 2: "REVERSE" : 0 + 4: "X_AXIS" : 0 + 8: "Y_AXIS" : 0 + ] + + speed(integer): "determines how fast it moves; default value is 100." : 100 + dmg(integer): "damage to inflict when blocked (2 default)." : 2 +] + +@SolidClass base(Appearflags, Target, Targetname) color(0 0.5 0.8) = func_wall : "Wall" +[ + spawnflags(Flags) = + [ + 1: "TRIGGER_SPAWN" : 0 + 2: "TOGGLE" : 0 + 4: "START_ON" : 0 + 8: "ANIMATED" : 0 + 16: "ANIMATED_FAST" : 0 + 32: "NOT_SOLID" : 0 + 64: "CTF_WALL_ONLY" : 0 + ] + + killtarget(string): "the targetname of the entity to remove when triggered" + cinescript(string): "name of the cinematic script to run when toggled" + aiscript(string): "name of the AI script to run when toggled" +] + +@SolidClass base(Appearflags, Target, Targetname) color(0 0.5 0.8) = func_button : "Button" +[ + spawnflags(Flags) = + [ + 1: "PUSH_TOUCH" : 0 + 2: "STRUGGLE" : 0 + ] + + killtarget(string): "the targetname of the entity to remove when triggered" + keyname(string): "if set, the player must have the specified item in their inventory i.e. 'item_crypt_key'" + sound_use(string): "the sound to play when the button is used (defaults to none)" + sound_return(string): "the sound to play when the button returns (defaults to none)" + speed(integer): "rate of travel when button moves" + wait(float): "seconds to wait befor returning to useable (-1 = never return) (default 1.0)" : 1.0 + angle(integer): "direction of travel" + lip(integer): "amount of button left sticking out after being pushed (default 4)" : 4 + health(integer): "when > 0 the button must be killed in order to fire" + cinescript(string): "name of the cinematic script to run" + aiscript(string): "name of the AI script to run" +] + +@SolidClass base(Appearflags, Target, Targetname) color(0 0.5 0.8) = func_multi_button : "Multi button" +[ + spawnflags(Flags) = + [ + 1: "PUSH_TOUCH" : 0 + 2: "CYCLE" : 0 + ] + + killtarget(string): "the targetname of the entity to remove when triggered" + sound_use(string): "the sound to play when the button is used (defaults to none)" + sound_return(string): "the sound to play when the button returns (defaults to none)" + speed(integer): "rate of travel when button moves" + wait(integer): "seconds to wait befor returning to useable (-1 = never return)" + angle(integer): "direction of travel" + health(integer): "when > 0 the button must be killed in order to fire" + distance(integer): "distance button travels on each push" + count(integer): "number of positions this button has" +] + +@PointClass base(Appearflags) color(0.5 0.3 0) size(-8 -8 -8, 8 8 8) = path_corner_train : "Tran path corner" +[ + spawnflags(Flags) = + [ + 1: "X_AXIS" : 0 + 2: "Y_AXIS" : 0 + 4: "Z_AXIS" : 0 + 8: "TRIGWAIT" : 0 + 16: "x" : 0 + 32: "TELEPORT" : 0 + 64: "x" : 0 + 128: "x" : 0 + ] + + killtarget(string): "the targetname of the entity to remove when this path_corner is reached" + speed(integer): "rate of travel from this path_corner to the next" + wait(integer): "seconds to wait after the actions on this path_corner are complete" + sound(string): "sound to play at this path corner" + x_distance(integer): "distance in degrees to rotate around x axis" + y_distance(integer): "distance in degrees to rotate around y axis" + z_distance(integer): "distance in degrees to rotate around z axis" + x_speed(integer): "speed to rotate along x axis in degrees per second" + y_speed(integer): "speed to rotate along y axis in degrees per second" + z_speed(integer): "speed to rotate along z axis in degrees per second" + health(integer): "if health is set, the train will wait at this path corner until it is killed." + pathtarget(string): "target to trigger when this path_corner is reached" + cinescript(string): "name of the cinematic script to run" + aiscript(string): "name of the AI script to run" +] + +@SolidClass base(Appearflags, Targetname) color(0 0.5 0.8) = func_door_secret : "Secret door" +[ + spawnflags(Flags) = + [ + 1: "OPEN_ONCE" : 0 + 2: "1ST_LEFT" : 0 + 4: "1ST_DOWN" : 0 + 8: "NO_SHOOT" : 0 + 16: "YES_SHOOT" : 0 + ] + + message(string): "printed when the door is touched if it is a trigger door and it hasn't been fired yet" + angle(integer): "determines the opening direction" + health(integer): "if set, door must be shot open" + speed(integer): "movement speed (100 default)" : 100 + wait(integer): "time to wait before returning (3 default, -1 = never return)" : 3 + dmg(integer): "damage to inflict when blocked (2 default)" : 2 + lip(integer): "lip" + sound_opening(string): "name of the sound to play during opening, ie. doors/creek.wav" + sound_open_finish(string): "name of the sound to play when opening completes, ie. doors/slam.wav" + sound_closing(string): "name of the sound to play when closing starts, ie. doors/creek.wav" + sound_close_finish(string): "name of the sound to play when closing completes, ie. doors/slam.wav" +] + +@SolidClass base(Appearflags, Target, Targetname) color(0 0.5 0.8) = func_wall_explode : "Exploding wall" +[ + spawnflags(Flags) = + [ + 1: "ROCK_CHUNKS" : 0 + 2: "WOOD_CHUNKS" : 0 + 4: "EXTRA_CHUNKS" : 0 + 8: "EXTRA_VELOCITY" : 0 + 16: "NO_CHUNKS" : 0 + 32: "NO_SOUND" : 0 + 64: "METAL_CHUNKS" : 0 + 128: "NO_EXPLOSIONS" : 0 + ] + + killtarget(string): "the targetname of the entity to remove when triggered" + health(integer): "ummm... this would be the health of the wall, if it is 0 then the wall can only be exploded by targetting it" + message(string): "this prints out when wall go boom" + model_1(string): "the specific pathname of the first model to throw when killed if model_1 is set then spawnflags ROCK_CHUNKS and WOOD_CHUNKS are overridden" + model_2(string): "the pathname of the second model" + model_3(string): "I wouldn't bet on it, but this is probably the name of the 3rd model" + group(string): "you can add a name here and group func_wall_explodes.. use triggerindex to specify priority of which one blows up first " + triggerindex(integer): "the lower the index, the higher it's priority (i.e. it blows up 1st func_wall_explodes with the same triggerindex blow up randomly" + mindamage(integer): "minimum damage it takes to destroy this wall. Any damage less than mindamage will be healed instantly so wall cannot be warn down." +] + +@SolidClass base(Appearflags, Target) color(0 0.5 0.8) = func_debris : "Debris" +[ + spawnflags(Flags) = + [ + 1: "GO_TO_ACTIVATOR" : 0 + 2: "NO_ROTATE" : 0 + 4: "MOMENTUM_DAMAGE" : 0 + 8: "NO_ROTATION_ADJUST" : 0 + 16: "DROP_ONLY" : 0 + 32: "QUARTER_SIZE" : 0 + ] + + fly_sound(string): "sound to play while the entity flies through the air" + hit_sound(string): "sound to play when the entity hits something" + volume(float): "0.0 to 1.0" + min(integer): "0 to 2040 - minimum distance (volume full)" + max(integer): "0 to 8160 - maximum distance (volume none)" + damage(integer): "amount of damage to do when hitting another object if MOMENTUM_DAMAGE is selected," +] + +@SolidClass base(Appearflags, Target) color(0 0.5 0.8) = func_debris_visible : "Visible debris" +[ + spawnflags(Flags) = + [ + 1: "GO_TO_ACTIVATOR" : 0 + 2: "NO_ROTATE" : 0 + 4: "MOMENTUM_DAMAGE" : 0 + 8: "NO_ROTATION_ADJUST" : 0 + 16: "DROP_ONLY" : 0 + 32: "QUARTER_SIZE" : 0 + ] + + fly_sound(string): "sound to play while the entity flies through the air" + hit_sound(string): "sound to play when the entity hits something" + volume(float): "0.0 to 1.0" + min(integer): "0 to 2040 - minimum distance (volume full)" + max(integer): "0 to 8160 - maximum distance (volume none)" + damage(integer): "amount of damage to do when hitting another object" +] + +@PointClass base(Appearflags) color(0 0.5 0.8) size(-8 -8 -8, 8 8 8) = func_dynalight : "Dynamic light" +[ + spawnflags(Flags) = + [ + 1: "START_ON" : 0 + 2: "SPOTLIGHT" : 0 + 4: "LIGHTFLARE" : 0 + 8: "X_AXIS" : 0 + 16: "Y_AXIS" : 0 + 32: "Z_AXIS" : 0 + 64: "REVERSE" : 0 + ] + + length(integer): "length of the light beam... default is 2048" : 2048 + light(integer): "light brightness value" + radius(integer): "radius of starting point, end radius is based on length default SPOTLIGHT color is white.. click color checkboxes to change colors" + _color(color255): "use the color selection dialog to select the color of the light" +] + +@SolidClass base(Appearflags, Target) color(0 0.5 0.8) = func_explosive : "Explosive" +[ + spawnflags(Flags) = + [ + 1: "TRIGGER_SPAWN" : 0 + 2: "ANIMATED" : 0 + 4: "ANIMATED_FAST" : 0 + 8: "STONE" : 0 + 16: "WOOD" : 0 + 32: "METAL" : 0 + 64: "NO_CHUNKS" : 0 + 128: "NO_SOUND" : 0 + 256: "NO_EXPLOSION" : 0 + 512: "NOT_SOLID" : 0 + ] + + damage(integer): "radius explosion of that amount, at center of brush" + health(integer): "defaults to 100." : 100 + delay(float): "defaults to 1.0 to randomize the emission of debris chunks. The higher the number the longer it will take some chunks to chunk out." : 1.0 + count(integer): "defaults to 10. This determines how many chunks are emitted. 10 = maximum of 10 chunks but is random so could be 5-10, no less than 5." : 10 + rndcount(integer): "defaults to 0. Random number of debris entities plus the count." : 0 + scale(float): "This is the scale factor of the chunks. 1.0 is current Size." : 1.0 + vectortarget(integer): "Sets the vector for the initial direction. It will be random in a 180 degree spread." + speed(float): "is a scaled value. 1.0 is normal speed." : 1.0 + gravity(float): "Gravity to apply to debris. Default is 1.0.(normal)" : 1.0 + cinescript(string): "name of the cinematic script to run" + aiscript(string): "name of the AI script to run" + volume(float): "0.0 to 1.0" + min(integer): "0 to 2040 - minimum distance (volume full)" + max(integer): "0 to 8160 - maximum distance (volume none)" +] + +@SolidClass base(Appearflags, Target, Targetname) color(0 0.5 0.8) = func_water : "Water" +[ + spawnflags(Flags) = + [ + 1: "START_OPEN" : 0 + 2: "x" : 0 + 4: "x" : 0 + 8: "x" : 0 + 16: "x" : 0 + 32: "x" : 0 + 64: "x" : 0 + 128: "x" : 0 + 256: "x" : 0 + 512: "FORCEMOVE" : 0 + ] + + angle(choices): "determines the opening direction (up or down only)" : -1 = + [ + -1: "Up" + -2: "Down" + ] + + speed(integer): "movement speed (25 default)" : 25 + wait(integer): "wait before returning (-1 default, -1 = TOGGLE)" : -1 + lip(integer): "lip remaining at end of move (0 default)" : 0 + sound_opening(string): "name of the sound to play when rising" + sound_open_finish(string): "name of the sound to play when at the top" + sound_closing(string): "name of the sound to play when receeding" + sound_close_finish(string): "name of the sound to play when empty" +] + +@PointClass base(Appearflags, Target, Targetname) color(0.3 0.1 0.6) size(-8 -8 -8, 8 8 8) = func_timer : "Timer" +[ + spawnflags(Flags) = + [ + 1: "START_ON" : 0 + 2: "USE_ONCE" : 0 + ] + + wait(integer): "base time between triggering all targets, default is 1" : 1 + random(integer): "wait variance, default is 0 so, the basic time between firing is a random time between (wait - random) and (wait + random)" + delay(integer): "delay before first firing when turned on, default is 0" : 0 + pausetime(integer): "additional delay used only the very first time and only if spawned with START_ON" +] + +@SolidClass base(Appearflags, Target, Targetname) color(0 0.5 0.8) = func_event_generator : "Event generator" +[ + spawnflags(Flags) = + [ + 1: "TRIGGER_ONCE" : 0 + 2: "TRIGGER_TOUCHABLE" : 0 + 4: "ALLOW_MONSTERS" : 0 + ] + + sound(string): "Sound to play when triggered." +] + +@SolidClass base(Appearflags, Target) color(0 0.5 0.8) = func_monitor : "Monitor" +[ + fov(integer): "the field of view when looking through this camera" + delay(integer): "Amount of time to delay before showing the monitor display." + wait(integer): "Amount of time to wait before allowing the user to esc from display." +] + +@SolidClass base(Appearflags, Target, Targetname) color(0 0.5 0.8) = func_train : "Train" +[ + spawnflags(Flags) = + [ + 1: "x" : 0 + 2: "x" : 0 + 4: "x" : 0 + 8: "x" : 0 + 16: "x" : 0 + 32: "x" : 0 + 64: "FORCEMOVE" : 0 + 128: "START_ON" : 0 + ] + + killtarget(string): "the targetname of the entity to remove when triggered" +] + + +// +// Triggers +// +@SolidClass base(Appearflags) color(0.5 0.5 0.5) = trigger_console : "Console" +[ + spawnflags(Flags) = + [ + 1: "USE_ONCE" : 0 + ] + + message(string): "the command to send to the console when triggered." +] + +@PointClass base(Appearflags, Target, Targetname) color(1 1 0) size(-8 -8 -8, 8 8 8) = target_attractor : "Attractor" +[ + triggerindex(integer): "the lower the index, the higher it's priority (i.e. it attracts 1st)." +] + +@SolidClass base(Appearflags) color(0.5 0.5 0.5) = trigger_changemusic : "Change music" +[ + path(string): "path to mp3 to play relative to data/music. ( include the extension )." + volume(float): "the volume to play the mp3 at ( 0 - 1 )." +] + +@SolidClass base(Appearflags) color(0.5 0.5 0.5) = trigger_superfly_spawn : "Superfly spawn" [] +@SolidClass base(Appearflags) color(0.5 0.5 0.5) = trigger_mikiko_spawn : "Mikiko spawn" [] + +@SolidClass base() color(0.5 0.5 0.5) = trigger_script: "Script" +[ + spawnflags(Flags) = + [ + 1: "MULTIPLE" : 0 + 2: "NOTOUCH" : 0 + 4: "SUPERFLY_REQUIRED" : 0 + 8: "MIKIKO_REQUIRED" : 0 + ] + + wait(float): "time to wait between retriggering (default = 2.0 seconds)" : 2.0 + delay(float): "delay after triggering before script runs ** doesn't work with touch triggers ** (default = 0.0 seconds)" : 0.0 + cinescript(string): "name of the cinematic script to run" + aiscript(string): "name of the AI script to run" + scriptname(string): "name of script to run" +] + +@SolidClass color(0.5 0.5 0.5) = trigger_remove_inventory_item : "Remove item from inventory" +[ + item(string): "the name of the item to remove from the inventory of the entity that touches the trigger ( e.g. weapon_daikatana )" +] + +@SolidClass color(0.5 0.5 0.5) = trigger_change_sfx : "Change SFX" +[ + spawnflags(Flags) = + [ + 1: "NORMAL" : 0 + 2: "PRESET1" : 0 + 4: "PRESET2" : 0 + 8: "PRESET3" : 0 + 16: "PRESET4" : 0 + ] + + fxstyle(string): "the effect style to be activated" + wait(integer): "the number of seconds to wait until triggering" + reverb(integer): "Reverb" + volume(integer): "default 100" : 100 +] + +@SolidClass color(0.5 0.5 0.5) = trigger_secret : "Secret" +[ + sound(string): "name of sound to play upon firing" + message(string): "message to display upon last triggering" +] + +@SolidClass base(Appearflags, Target, Targetname) color(0.5 0.5 0.5) = trigger_sidekick : "Sidekick trigger" +[ + toggle(choices): "Toggle - 0 = off, 1 = on" : 0 = + [ + 0: "Disabled" + 1: "Enabled" + ] + + sidekick(string): "Choose a sidekick to activate ('Mikiko' or 'Superfly')": "Superfly" + sound(string): "name of sound to play upon triggering" + message(string): "message to display upon last triggering" +] + +@SolidClass base(Appearflags, Target, Targetname) color(0.5 0.5 0.5) = trigger_multiple : "Multiple trigger" +[ + spawnflags(Flags) = + [ + 1: "NOTOUCH" : 0 + 2: "ALLOW_MONSTERS" : 0 + 4: "ALLOW_SIDEKICKS" : 0 + ] + + health(integer): "if set the trigger must be killed to activate" + delay(integer): "time to wait after activation before firing target" + wait(float): "time to wait between retriggering (default = 0.2 seconds)" : 0.2 +] + +@SolidClass base(Appearflags) color(0.5 0.5 0.5) = trigger_sidekick_teleport : "Teleport sidekick" +[ + spawnflags(Flags) = + [ + 1: "TELEPORT_AND_STAY" : 0 + 2: "TELEPORT_AND_COME_TO_OWNER" : 0 + 4: "MULTIUSE" : 0 + ] + + sound(string): "name of sound to play upon triggering" + animation(string): "animtion to play when triggered" + wait(integer): "seconds between activations if MULTIUSE flag is set" + x(integer): "x location of for the sidekicks to move when triggered" + y(integer): "y location of for the sidekicks to move when triggered" + z(integer): "z location of for the sidekicks to move when triggered" +] + +@SolidClass base(Appearflags) color(0.5 0.5 0.5) = trigger_sidekick_stop : "Stop sidekick" +[ + sound(string): "name of sound to play upon triggering" + animation(string): "animtion to play when triggered" + x(integer): "x location of for the sidekicks to move when triggered" + y(integer): "y location of for the sidekicks to move when triggered" + z(integer): "z location of for the sidekicks to move when triggered" +] + +@SolidClass base(Appearflags, Target) color(0.5 0.5 0.5) = trigger_changelevel : "Change level" +[ + spawnflags(Flags) = + [ + 1: "INTERMISSION" : 0 + 2: "REQUIRES_SUPERFLY" : 0 + 4: "REQUIRES_MIKIKO" : 0 + 8: "THE_END" : 0 + 16: "KEEP_SIDEKICKS" : 0 + ] + + sound(string): "name of sound to play upon firing" + map(string): "the name of the map to go to" + cinematic(string): "name of cinematic to play before exiting" +] + +@SolidClass base(Appearflags) color(0.5 0.5 0.5) = trigger_counter : "Counter" +[ + spawnflags(Flags) = + [ + 1: "NO_MESSAGE" : 0 + 2: "NO_TOUCH" : 0 + 4: "INCLUDE_MONSTERS" : 0 + ] + + count(integer): "number of times to trigger before firing" + sound(string): "name of sound to play upon firing" + message(string): "message to display upon last triggering" +] + +@SolidClass base(Appearflags) color(0.5 0.5 0.5) = trigger_push : "Push trigger" +[ + spawnflags(Flags) = + [ + 1: "PUSH_ONCE" : 0 + 2: "ALLOW_TOGGLE" : 0 + 4: "START_DISABLED" : 0 + ] + + speed(integer): "the velocity to give the object (default 1000)" : 1000 + sound(string): "the wave to play when triggered" + message(string): "text message to display when triggered" +] + +@SolidClass base(Appearflags, Target, Targetname) color(0.5 0.5 0.5) = trigger_teleport : "Teleport trigger" +[ + spawnflags(Flags) = + [ + 1: "PLAYER_ONLY" : 0 + 2: "NO_FLASH" : 0 + 4: "NO_ANGLE_ADJUST" : 0 + ] + + sound(string): "name of sound to play upon firing, if not specified, then no sound will be played" + fog_value(integer): "sets fog_value to this when a teleporter is used" + killtarget(string): "the targetname of the entity to remove when triggered" + message(string): "text message to display when triggered" +] + +@SolidClass base(Appearflags, Targetname) color(0.5 0.5 0.5) = trigger_once : "triggers once, then removes itself" +[ + spawnflags(Flags) = + [ + 1: "NOTOUCH" : 0 + 2: "ALLOW_MONSTERS" : 0 + 4: "ALLOW_SIDEKICKS" : 0 + ] + + health(integer): "if set the trigger must be killed to activate" + delay(integer): "time to wait after activation before firing target" + wait(float): "time to wait between retriggering (default = 0.2 seconds)" : 0.2 + sound(string): "name of sound to play upon firing" + killtarget(string): "the targetname of the entity to remove when triggered" + message(string): "text message to display when triggered" +] + +@SolidClass base(Appearflags, Target, Targetname) color(0.5 0.5 0.5) = trigger_toggle : "triggers once, then when you exit resets itself to be triggered again" +[ + spawnflags(Flags) = + [ + 1: "USE_ON_EXIT" : 0 + 2: "ALLOW_MONSTERS" : 0 + 4: "ALLOW_SIDEKICKS" : 0 + 8: "SIDEKICKS_ONLY" : 0 + ] +] + +@PointClass base(Appearflags, Targetname, Target) color(0.5 0.5 0.5) size(-8 -8 -8, 8 8 8) = trigger_relay : "Relay trigger" +[ + sound(string): "name of sound to play upon firing" + delay(integer): "delay" + killtarget(string): "the targetname of the entity to remove when triggered" + message(string): "text message to display when triggered" +] + +@PointClass base(Appearflags, Targetname, Target) color(0.5 0.5 0.5) size(-8 -8 -8, 8 8 8) = trigger_changetarget : "Change target trigger" +[ + spawnflags(Flags) = + [ + 1: "USE_ONCE" : 0 + ] + + newtarget(string): "new target for the targetted entity" +] + +@SolidClass base(Appearflags, Target, Targetname) color(0.5 0.5 0.5) = trigger_hurt : "Hurt trigger" +[ + spawnflags(Flags) = + [ + 1: "ALLOW_TOGGLE" : 0 + 2: "START_DISABLED" : 0 + 4: "FLOWTHRU_DMG" : 0 + ] + + message(string): "text message to display when triggered" + sound(string): "name of sound to play upon firing" + dmg(integer): "the amount of damage the trigger will do to an object" + wait(integer): "the number of seconds between triggerings and" +] + + +// +// Targets +// +@BaseClass = TargetTriggers +[ + spawnflags(Flags) = + [ + 1: "TARGET_1" : 0 + 2: "TARGET_2" : 0 + 4: "TARGET_3" : 0 + 8: "TARGET_4" : 0 + 16: "TARGET_5" : 0 + 32: "TARGET_6" : 0 + 64: "TARGET_7" : 0 + 128: "TARGET_8" : 0 + ] +] + +@PointClass base(Appearflags, TargetTriggers) color(0.5 0.5 0.5) size(-8 -8 -8, 8 8 8) = target_crosslevel_target : "Crosslevel Target" [] +@PointClass base(Appearflags, TargetTriggers) color(0.5 0.5 0.5) size(-8 -8 -8, 8 8 8) = target_crosslevel_trigger : "Crosslevel Trigger" [] + +@PointClass base(Appearflags, Target) color(0 0.5 0.8) size(-8 -8 -8, 8 8 8) = target_laser : "Laser" +[ + spawnflags(Flags) = + [ + 1: "START_ON" : 0 + 2: "RED" : 0 + 4: "GREEN" : 0 + 8: "BLUE" : 0 + 16: "YELLOW" : 0 + 32: "LIGHTRED" : 0 + 64: "WIDE_BEAM" : 0 + ] + + angle(integer): "direction of laser" + sound(string): "the looping sound a laser will play when activated." +] + +@PointClass base(Appearflags) color(0 0.5 0.8) size(-8 -8 -8, 8 8 8) = target_earthquake : "Earthquake" +[ + speed(integer): "severity/speed of quake" + count(integer): "length/duration of quake in seconds" + damage(integer): "damage amount per frame" + radius(integer): "radius quake effects" + mins(float): "mins attenuation start point from earthquake spawn point(for sound)(default 2000.0f)" + maxs(float): "maxs attenuation end point from earthquake spawn point(end of sound)(default 2024.0f)" +] + +@PointClass base(Appearflags) color(0 0.5 0.8) size(-8 -8 -8, 8 8 8) = target_spotlight : "Spotlight" +[ + spawnflags(Flags) = + [ + 1: "START_ON" : 0 + 2: "RED" : 0 + 4: "GREEN" : 0 + 8: "BLUE" : 0 + 16: "YELLOW" : 0 + 32: "LIGHTRED" : 0 + ] + + length(integer): "length of the light beam.. default is 2048" : 2048 + radius(integer): "radius of starting point, end radius is based on length" + _color(color255): "default color is white.. click color checkboxes to change colors" +] + +@PointClass base(Appearflags) color(0 0.5 0.8) size(-8 -8 -8, 8 8 8) = target_lightramp : "Lightramp" +[ + spawnflags(Flags) = + [ + 1: "TOGGLE" : 0 + ] + + speed(integer): "How many seconds the ramping will take" + message(string): "two letters; starting lightlevel and ending lightlevel" +] + +@PointClass base(Appearflags) color(0 1 1) size(-8 -8 -24, 8 8 8) = target_monster_spawn : "Monster spawn" +[ + spawnflags(Flags) = + [ + 1 : "WANDER" : 0 + 2 : "PATHFOLLOW" : 0 + 4 : "NODE_WANDER" : 0 + 8 : "RANDOM_WANDER" : 0 + 16 : "IGNORE_PLAYER" : 0 + 32 : "SNIPE" : 0 + 64 : "DO_NOT_FLY" : 0 + 128 : "DO_NOT_MOVE" : 0 + 256 : "x" : 0 + 512 : "TAKE_COVER" : 0 + 1024 : "ALWAYS_GIB" : 0 + ] + + monsterclass(string): "exact classname of monster to spawn" + sound(string): "wave file to play when the monster is spawned" + aistate(string): "AI state (see list) for monster to immediately do" +] + +@PointClass base(Appearflags, Target, Targetname) color(0 1 0.5) size(-8 -8 -8, 8 8 8) = target_speaker : "Speaker" +[ + spawnflags(Flags) = + [ + 1: "LOOPED_ON" : 0 + 2: "LOOPED_OFF" : 0 + 4: "RELIABLE" : 0 + 8: "NON_DIRECTIONAL" : 0 + 16: "START_OFF" : 0 + ] + + sound(string): "wav file to play, where # represents 1-6 multiple wav files activate random play mode" + sound1(string): "wav file to play, where # represents 1-6 multiple wav files activate random play mode" + sound2(string): "wav file to play, where # represents 1-6 multiple wav files activate random play mode" + sound3(string): "wav file to play, where # represents 1-6 multiple wav files activate random play mode" + sound4(string): "wav file to play, where # represents 1-6 multiple wav files activate random play mode" + sound5(string): "wav file to play, where # represents 1-6 multiple wav files activate random play mode" + sound6(string): "wav file to play, where # represents 1-6 multiple wav files activate random play mode" + delay(integer): "0 default - seconds between random play" : 0 + mindelay(integer): "0 default - minimum seconds between random playings" : 0 + volume(float): "0.0 to 1.0" + min(integer): "0 to 2040 - minimum distance (volume full)" + max(integer): "0 to 8160 - maximum distance (volume none)" +] + +@PointClass base(Appearflags, Target, Targetname) color(0 0.5 0.8) size(-8 -8 -8, 8 8 8) = target_effect : "Effect" +[ + spawnflags(Flags) = + [ + 1: "START_ON" : 0 + 2: "TARGET_EFFECT_BEAMS" : 0 + 4: "TARGET_EFFECT_RANDOM" : 0 + 8: "TARGET_EFFECT_BEAMS_SMOKE" : 0 + ] + + gravity(choices): "gravity type" : 1 = + [ + 0: "FALL" + 1: "RISE (default)" + 2: "FLOAT" + ] + + type(choices): "particle type": 5 = + [ + 0: "SIMPLE" + 1: "SNOW" + 2: "RAIN" + 3: "BLOOD" + 4: "BUBBLE" + 5: "SMOKE (default)" + 6: "SPARKS" + 7: "BIG SPARKS" + 8: "POISON" + 9: "BLUE SPARKS" + 10: "ICE" + ] + + angle(integer): "determines the direction the particles will go" + _color(color255): "color of the particles" + speed(integer): "speed of particles (default=5)" : 5 + count(integer): "number of particles to create (default=10) (max=64)" : 10 + length(integer): "length in seconds to spawn particles (default = 1 frame)" : 1 + frametime(float): "length of time between particle spawns (default=0.10)" : 0.10 + sound(string): "wave file to play when the particles are spawned" +] + + +// +// Decorations +// +@PointClass base(Appearflags, Target, Targetname) color(1 0 0) size(-8 -8 -32, 8 8 32) = deco_custom : "Custom decoration" +[ + spawnflags(Flags) = + [ + 1: "DECO_EXPLODE" : 0 + 2: "NO_EXPLODE_NO_BREAK" : 0 + 4: "DECO_PUSHABLE" : 0 + 8: "WOOD_DEBRIS" : 0 + 16: "METAL_DEBRIS" : 0 + 32: "GLASS_DEBRIS" : 0 + 64: "GIB_DEBRIS" : 0 + 128: "ROTATE" : 0 + 256: "DECO_TRANSLUCENT" : 0 + ] + + exploding(choices): "0 or 1" : 0 = + [ + 0: "False" + 1: "True" + ] + + damage(integer): "damage applied when exploding. Default is 15." : 15 + scale(float): "Scale of deco. Default 1.0." : 1.0 + model(string): "filename of .dkm model, e.g. models/e1/a_c4.dkm" + mass(float): "default 1.0" : 1.0 + frame(integer): "allows you to specify the starting frame for the model." + x_speed(integer): "speed to rotate along x axis in degrees per second" + y_speed(integer): "speed to rotate along y axis in degrees per second" + z_speed(integer): "speed to rotate along z axis in degrees per second" + alpha(float): "range 0.0-1.0. Only used if TRANSLUCENT is flagged" + spawnname(string): "classname of entity to throw out upon death" + movetype(string): "none, toss, bounce, float" : "none" + solidtype(string): "bbox, not" : "bbox" + gibtype(string): "wood, metal, glass, gibs, default is non-gibbable" : "non-gibbable" + hitpoints(integer): "default 20" : 20 + mins(string): "bbox lower bounds, e.g. -8, -8, -32" + maxs(string): "bbox upper bounds, eg.g. 8, 8, 32" + animseq(integer): "allows you to specifies an animation sequence for the model this overrides the frame key.. valid sequences are 0-4 DEFAULT is 0": 0 + seq0-seq4(string): "frames or frame sequences of animation use '-' for a set of frames use '~' to loop the frames" +] + + +// +// Information +// +@BaseClass base(Appearflags, Targetname) color(1 0 0) size(-16 -16 -24, 16 16 32) = PlayerClass [] +@BaseClass base(Appearflags, Targetname) color(1 0 0) size(-8 -8 -8, 8 8 8) = CameraClass [] +@BaseClass base(Appearflags, Targetname) color(0.5 0.5 0.5) size(-8 -8 -8, 8 8 8) = TeleportClass [] + +@BaseClass = PlayerWeaponOverride +[ + spawnflags(Flags) = + [ + 1: "OVERRIDE_WEAPONS" : 0 + 2: "WEAPON_1" : 0 + 4: "WEAPON_2" : 0 + 8: "WEAPON_3" : 0 + 16: "WEAPON_4" : 0 + 32: "WEAPON_5" : 0 + 64: "WEAPON_6" : 0 + 128: "WEAPON_7" : 0 + ] +] + +@BaseClass = SidekickIdle +[ + spawnflags(Flags) = + [ + 1: "IDLE" : 0 + ] +] + +@PointClass base(TeleportClass) = info_teleport_destination : "Teleport Destination - Point teleporters at this. Duh." [] +@PointClass base(CameraClass) = info_camera : "Camera" [] +@PointClass base(CameraClass) = info_null : "Null point" [] +@PointClass base(CameraClass) = info_not_null : "Not null point" [] + +@PointClass base(CameraClass) = info_player_intermission : "Intermission camera point." +[ + angles(string) : "pitch yaw roll" +] + +@PointClass base(PlayerClass) = info_player_start : "Location player starts in single play." +[ + spawnflags(Flags) = + [ + 1: "NO_OFFSET" : 0 + ] +] + +@PointClass base(PlayerClass, SidekickIdle) = info_mikiko_start : "Location Mikiko starts in single play." [] +@PointClass base(PlayerClass, SidekickIdle) = info_superfly_start : "Location Superfly starts in single play." [] +@PointClass base(PlayerClass, SidekickIdle) = info_mikikofly_start : "Location mikikofly starts in single play." [] +@PointClass base(PlayerClass, PlayerWeaponOverride) color(1 0 1) = info_player_deathmatch : "Location player starts in deathmatch." [] +@PointClass base(PlayerClass, PlayerWeaponOverride) color(1 0 1) = info_player_coop : "Location player starts in coop." [] +@PointClass base(PlayerClass, PlayerWeaponOverride) = info_player_team1 : "Location player on team 1 starts." [] +@PointClass base(PlayerClass, PlayerWeaponOverride) color(0 0 1) = info_player_team2 : "Location player on team 2 starts." [] + + +// +// Sound +// +@PointClass base(Appearflags, Target, Targetname) color(1 0 1) size(-8 -8 -8, 8 8 8) = sound_ambient : "Ambient Sound" +[ + spawnflags(Flags) = + [ + 1: "x" : 0 + 2: "x" : 0 + 4: "x" : 0 + 8: "NON_DIRECTIONAL" : 0 + ] + + sound(string): "path to ambient sound (ie. ambience/sound.wav.)" +] + + +// +// Node +// +@PointClass base(Appearflags, Target, Targetname) color(0.5 0.5 1) size(-8 -8 -8, 8 8 8) = node_node : "Node" +[ + number(integer): "the number of this node" + link(integer): "the number of the node linked to (can be up to four link fields)" +] + + +// +// Monsters +// +@PointClass base(Appearflags, Target, Targetname) color(0.5 0.3 0) size(-8 -8 -8, 8 8 8) = monster_path_corner : "A path corner for a monster to travel along" +[ + target1(string): "Target 1" + target2(string): "Target 2" + target3(string): "Target 3" + target4(string): "Target 4" + pathtarget(string): "target of entity that will get called upon hitting this pathcorner. This is a one shot deal." + aiscript(string): "name of the script to play when a monster hits this pathcorner node." +] + + +// +// Animals +// +@PointClass base(Animal) model({ "path": "models/global/d4_gull.dkm" }) = e_seagull : "Seagull" [] +@PointClass base(Animal) model({ "path": "models/global/e_goldfish.dkm" }) = fish_goldfish : "Goldfish" [] +@PointClass base(Animal) model({ "path": "models/global/e_greyfish.dkm" }) = fish_grayfish : "Grayfish" [] +@PointClass base(Animal) model({ "path": "models/global/e_guppy.dkm" }) = fish_guppy1 : "Guppy 1" [] +@PointClass base(Animal) model({ "path": "models/global/e_guppy2.dkm" }) = fish_guppy2 : " Guppy 2" [] +@PointClass base(Animal) color(0.5 0.5 0) size(-40 -40 -40, 40 40 40) model({ "path": "models/global/dopefish.dkm" }) = fish_dopefish : "Dopefish" [] + + +// +// Items +// +@BaseClass base(Appearflags, Target, Sidekickflags) color(0 0.5 0.8) size(-16 -16 -24, 16 16 8) = HealthItems +[ + team(string) : "Team" +] + +@BaseClass base(Appearflags, Target) = ShieldItems +[ + team(string) : "Team" +] + +@PointClass base(HealthItems) model({ "path": "models/global/a_gsoul.dkm" }) = item_goldensoul : "Maxes health to twice vitality." [] +@PointClass base(HealthItems) model({ "path": "models/e1/a1_hlth.dkm" }) = item_health_25 : "Gives 25 health" [] +@PointClass base(HealthItems) model({ "path": "models/e1/a1_hlth2.dkm" }) = item_health_50 : "Gives 50 health" [] +@PointClass base(ShieldItems) color(0 0.5 0.8) size(-16 -16 -16, 16 16 24) model({ "path": "models/global/a_mshield.dkm" }) = item_megashield : "Gives 400 armor." [] +@PointClass base(Appearflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/global/a_invincibility.dkm" }) = item_invincibility : "30 seconds of invulnerability." [] +@PointClass base(Appearflags) color(0.3 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/global/a_savegem.dkm" }) = item_savegem : "Save gems are stored in the inventory, and used to save games." [] +@PointClass base(Appearflags) color(0 0.5 0.8) size(-16 -16 -24, 16 16 8) model({ "path": "models/global/a_wraithorb.dkm" }) = item_wraithorb : "20% translucency, unlessed stopped, in which case the player is completely invisible. Lasts 60 seconds." [] +@PointClass base(Appearflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/global/a_pwrb.dkm" }) = item_power_boost : "30 second boost to attack power." [] +@PointClass base(Appearflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/global/a_atkb.dkm" }) = item_attack_boost : "30 second boost to attack speed." [] +@PointClass base(Appearflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/global/a_spdb.dkm" }) = item_speed_boost : "30 second boost to movement speed." [] +@PointClass base(Appearflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/global/a_acrb.dkm" }) = item_acro_boost : "30 second boost to jump height." [] +@PointClass base(Appearflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/global/a_vtlb.dkm" }) = item_vita_boost : "30 second boost to vitality." [] + +@SolidClass base(Appearflags) color(0.5 0.5 0.5) = trigger_capture : "Specifies a capture area for ctf/deathtag." +[ + spawnflags(Flags) = + [ + 1: "TEAM1" : 0 + 2: "TEAM2" : 0 + ] + + POINTS(integer): "Number of points awarded for a capture." +] + +@BaseClass = NPCAnyDirection +[ + spawnflags(Flags) = + [ + 1: "ANY_DIR" : 0 + ] + + sfly_msg(string): "message for superfly to say when hitting this trigger" + miko_msg(string): "message for mikiko to say when hitting this trigger" +] + +@PointClass base(Appearflags) color(0.5 0.5 0.5) size(-16 -16 -24, 16 16 32) = NPCteleport_dest : "NPC Teleport Destination Area" [] + +@SolidClass base(Appearflags, NPCAnyDirection) color(0.5 0.5 0.5) = NPCtrigger_waithere : "Makes superfly and/or Mikiko stop and wait until a new goal is" +[ + angle(integer): "the angle the NPC must be moving to activate the trigger, +/- 45 degrees." +] + +@SolidClass base(Appearflags, NPCAnyDirection) color(0.5 0.5 0.5) = NPCtrigger_stopwaithere : "Only clients can trigger this. It will inform all waiting NPCs" +[ + angle(integer): "the angle the CLIENT must be moving to activate the trigger, +/- 45 degrees." +] + +@SolidClass base(Appearflags, NPCAnyDirection) color(0.5 0.5 0.5) = NPCtrigger_teleport : "Only clients can trigger this. It will teleport all NPCs owned" +[ + angle(integer): "the angle the CLIENT must be moving to activate the trigger, +/- 45 degrees." + sfly_target(string): "targetname of entity Superfly will teleport to" + miko_target(string): "targetname of entity Mikiko will teleport to" +] + +@PointClass color(0.8 0 0) size(-8 -8 -8, 8 8 8) = item_flag_team1 : "Team 1 Flag" +[ + FLAGCOLOR(choices): "Default is red" : 1 = + [ + 1 : "red" + 2 : "blue" + 3 : "chrome" + 4 : "metal" + 5 : "green" + 6 : "orange" + 7 : "purple" + 8 : "yellow" + ] +] + +@PointClass color(0 0 0.8) size(-8 -8 -8, 8 8 8) = item_flag_team2 : "Team 2 Flag" +[ + FLAGCOLOR(choices): "Default is blue" : 2 = + [ + 1 : "red" + 2 : "blue" + 3 : "chrome" + 4 : "metal" + 5 : "green" + 6 : "orange" + 7 : "purple" + 8 : "yellow" + ] +] diff --git a/tools/trenchbroom/games/Daikatana/Episode 1.fgd b/tools/trenchbroom/games/Daikatana/Episode 1.fgd new file mode 100644 index 0000000..38eeeac --- /dev/null +++ b/tools/trenchbroom/games/Daikatana/Episode 1.fgd @@ -0,0 +1,117 @@ +// +// Daikatana game definition file (.fgd) +// Episode 1 entities +// for Trenchbroom +// last update: 6 Oct, 2018 +// Version: 1 +// +// written by Dekonega +// email me with improvements and suggestions +// + +@include "Common.fgd" + + +// +// Items (Episode 1) +// +@PointClass base(Appearflags, KeyFlags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e1/a1_clcrd.dkm" }) = item_keycard_cell : "E1 prison cell key" [] +@PointClass base(Appearflags, Sidekickflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e1/a1_ar2.dkm" }) = item_chromatic_armor : "Chromatic armor" [] +@PointClass base(Appearflags, Sidekickflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e1/a1_ar1.dkm" }) = item_plasteel_armor : "Plasteel armor" [] + + +// +// Monsters (Episode 1) +// +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 8) model({ "path": "models/e1/m_croco.dkm" }) = monster_crox : "Crox" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 40) model({ "path": "models/e1/m_mwsurgeon.dkm" }) = monster_surgeon : "Surgeon" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 40) model({ "path": "models/e1/m_mwguard.dkm" }) = monster_mishimaguard : "Mishima guard" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e1/m_MWFaty.dkm" }) = monster_fatworker : "Fat worker" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 40) model({ "path": "models/e1/m_MWSkny.dkm" }) = monster_skinnyworker : "Skinny worker" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-12 -12 0, 12 12 24) model({ "path": "models/e1/m_proto.dkm" }) = monster_protopod : "Protopod" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-24 -24 -16, 24 24 32) model({ "path": "models/e1/m_dsphere.dkm" }) = monster_deathsphere : "Deathsphere" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-24 -24 -24, 24 24 24) model({ "path": "models/e1/m_cambot.dkm" }) = monster_cambot : "Cambot" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-40 -40 -40, 40 40 48) model({ "path": "models/e1/m_ragemaster.dkm" }) = monster_ragemaster : "Ragemaster" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-24 -24 -16, 24 24 24) model({ "path": "models/e1/m_bboar.dkm" }) = monster_battleboar : "Battle boar" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 36) model({ "path": "models/e1/m_cryotech.dkm" }) = monster_cryotech : "Cryotech" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-24 -24 -24, 24 24 32) model({ "path": "models/e1/m_psyclaw.dkm" }) = monster_psyclaw : "Psyclaw" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -8, 16 16 8) model({ "path": "models/e1/m_trakatak.dkm" }) = monster_lasergat : "Lasergat" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-32 -32 -40, 32 32 48) model({ "path": "models/e1/m_inmater.dkm" }) = monster_inmater : "Inmater" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e1/m_prizb.dkm" }) = monster_prisonerb : "Prisoner B" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e1/m_priza.dkm" }) = monster_prisoner : "Prisoner" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-40 -40 -40, 40 40 56) model({ "path": "models/e1/m_sludgeminion.dkm" }) = monster_sludgeminion : "Sludgeminion" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -8, 16 16 16) model({ "path": "models/e1/m_vermin.dkm" }) = monster_venomvermin : "Venomvermin" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-40 -40 0, 40 40 96) model({ "path": "models/e1/m_tskeet.dkm" }) = monster_thunderskeet : "Thunderskeet" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -8, 16 16 8) model({ "path": "models/e1/m_skeeter.dkm" }) = monster_slaughterskeet : "Roboskeet" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-8 -8 -16, 8 8 16) model({ "path": "models/e1/m_frog.dkm" }) = monster_froginator : "Froginator" [] + +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -16, 16 16 16) model({ "path": "models/e1/a1_rockgun.dkm" }) = monster_rockgat : "Rockgat" +[ + fire_rate(float): "secs between firing default = 0.20" : 0.20 + range(integer): "attack radius default = 512" : 512 + basedmg(integer): "dmg done with a hit" + rnddmg(integer): "random damage amount added on" + health(integer): "health value" +] + +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-8 -8 -8, 8 8 8) model({ "path": "models/global/e_flare.sp2" }) = monster_firefly : "Firefly" +[ + spawnflags(Flags) = + [ + 1: "YELLOW" : 0 + 2: "GREEN" : 0 + 4: "BLUE" : 0 + 8: "WHITE" : 0 + 16: "RED" : 0 + ] + + count(integer): "Number of fireflies(Max=10)" + distance(integer): "How far the fireflies will fly from point of placement(Max=200)" + velocity(integer): "How fast the fireflies will move(Max=200)" + scale(float): "How big the fireflies will be(1 = normal, 0.5 = half, 2 = twice as big)" + delta_alpha(float): "frequency of Alpha blending change. " + alpha_level(float): "Initial Setting for Alpha blending change." +] + + +// +// Decorations (Episode 1) +// +@PointClass base(Appearflags, DecorationFlags) color(1 0 0) size(-8 -8 -32, 8 8 32) = deco_e1 : "Episode 1 decoration" +[ + damage(integer): "damage applied when exploding. Default is 15." : 15 + scale(float): "Scale of deco. Default 1.0." : 1.0 + model(string): "choose model # -- see list." + mass(float): "*optional* - including this overrides the mass value in decoinfo.txt" + frame(integer): "allows you to specify the starting frame for the model." + animseq(integer): "allows you to specify an animation sequence for the model" + x_speed(integer): "speed to rotate along x axis in degrees per second" + y_speed(integer): "speed to rotate along y axis in degrees per second" + z_speed(integer): "speed to rotate along z axis in degrees per second" + alpha(float): "range 0.0-1.0. Only used if TRANSLUCENT is flagged" + spawnname(string): "classname of entity to throw out upon death" + movetype(string): "none, toss, bounce, float, overrides value in e1decoinfo.csv" : "none" +] + + +// +// Weapons (Episode 1) +// +@PointClass base(Weapons) model({ "path": ":models/e1/a_tazer.dkm" }) = weapon_disruptor : "Disruptor Glove" [] +@PointClass base(Weapons) model({ "path": ":models/e1/a_ion.dkm" }) = weapon_ionblaster : "Ion Blaster - ION blaster thingy" [] +@PointClass base(Weapons) model({ "path": ":models/e1/a_shot.dkm" }) = weapon_shotcycler : "Shotcycler-6" [] +@PointClass base(Weapons) model({ "path": ":models/e1/a_c4.dkm" }) = weapon_c4viz : "C4 Vizatergo" [] +@PointClass base(Weapons) model({ "path": ":models/e1/a_swindr.dkm" }) = weapon_sidewinder : "Sidewinder" [] +@PointClass base(Weapons) model({ "path": ":models/e1/a_shokwv.dkm" }) = weapon_shockwave : "Shockwave" [] +@PointClass base(Weapons) model({ "path": ":models/e1/a_gashand.dkm" }) = weapon_gashands : "Ultimate Gashands" [] +@PointClass base(Weapons) model({ "path": ":models/global/a_daikatana.dkm" }) = weapon_daikatana : "Daikatana" [] + + +// +// Ammo (Episode 1) +// +@PointClass base(Ammo) model({ "path": ":models/e1/wa_ion.dkm" }) = ammo_ionpack : "50 ion cells." [] +@PointClass base(Ammo) model({ "path": ":models/e1/wa_c4.dkm" }) = ammo_c4 : "8 C4 Modules." [] +@PointClass base(Ammo) model({ "path": ":models/e1/wa_shot6.dkm" }) = ammo_shells : "24 shotcycler shells." [] +@PointClass base(Ammo) model({ "path": ":models/e1/wa_swindr.dkm" }) = ammo_rockets : "18 rockets." [] +@PointClass base(Ammo) model({ "path": ":models/e1/wa_shokwv.dkm" }) = ammo_shocksphere : "2 ShockSpheres." [] diff --git a/tools/trenchbroom/games/Daikatana/Episode 2.fgd b/tools/trenchbroom/games/Daikatana/Episode 2.fgd new file mode 100644 index 0000000..910a264 --- /dev/null +++ b/tools/trenchbroom/games/Daikatana/Episode 2.fgd @@ -0,0 +1,84 @@ +// +// Daikatana game definition file (.fgd) +// Episode 2 entities +// for Trenchbroom +// last update: 6 Oct, 2018 +// Version: 1 +// +// written by Dekonega +// email me with improvements and suggestions +// + +@include "Common.fgd" + + +// +// Items (Episode 2) +// +@PointClass base(Appearflags, Sidekickflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e2/a2_ar2.dkm" }) = item_gold_armor : "Gold armor" [] +@PointClass base(Appearflags, Sidekickflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e2/a2_ar1.dkm" }) = item_silver_armor : "Silver armor" [] +@PointClass base(Appearflags, KeyFlags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e2/c_runes.dkm" }) = item_rune_s : "Rune S" [] +@PointClass base(Appearflags, KeyFlags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e2/c_runei.dkm" }) = item_rune_i : "Rune I" [] +@PointClass base(Appearflags, KeyFlags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e2/c_runeg.dkm" }) = item_rune_g : "Rune G" [] +@PointClass base(Appearflags, KeyFlags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e2/c_runee.dkm" }) = item_rune_e : "Rune E" [] +@PointClass base(Appearflags, KeyFlags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e2/c_runea.dkm" }) = item_rune_a : "Rune A" [] +@PointClass base(Appearflags, KeyFlags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e2/a2_horn.dkm" }) = item_horn : "Horn" [] +@PointClass base(Appearflags, KeyFlags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e2/a2_drachma.dkm" }) = item_drachma : "Drachma" [] +@PointClass base(Appearflags, AntidoteFlags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/global/a_antidote.dkm" }) = item_antidote : "Cures poisonous wound." [] + + +// +// Monsters (Episode 2) +// +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-32 -32 -24, 32 32 64) model({ "path": "models/e2/m_cyclops.dkm" }) = monster_cyclops : "Cyclops" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-32 -32 -24, 32 32 40) model({ "path": "models/e2/m_medusa.dkm" }) = monster_medusa : "Medusa" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e2/m_centurion.dkm" }) = monster_centurion : "Centurion" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e2/m_thief.dkm" }) = monster_thief : "Thief" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e2/m_cerberus.dkm" }) = monster_cerberus : "Cerberus" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-24 -24 -24, 24 24 56) model({ "path": "models/e2/m_column.dkm" }) = monster_column : "Column" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-20 -20 -24, 20 20 40) model({ "path": "models/e2/m_satyr.dkm" }) = monster_satyr : "Satyr" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-20 -20 -24, 20 20 32) model({ "path": "models/e2/m_ferryman.dkm" }) = monster_ferryman : "Ferryman" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-20 -20 -24, 20 20 40) model({ "path": "models/e2/m_harpy.dkm" }) = monster_harpy : "Harpy" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-40 -40 -24, 40 40 64) model({ "path": "models/e2/m_griffon.dkm" }) = monster_griffon : "Griffon" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-8 -8 -8, 8 8 8) model({ "path": "models/e2/m_spider.dkm" }) = monster_smallspider : "Small spider" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-32 -32 -8, 32 32 24) model({ "path": "models/e2/m_spider.dkm" }) = monster_spider : "Spider" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e2/m_skeleton.dkm" }) = monster_skeleton : "Skeleton" [] + + +// +// Decorations (Episode 2) +// +@PointClass base(Appearflags, DecorationFlags) color(1 0 0) size(-8 -8 -32, 8 8 32) = deco_e2 : "Episode 2 decoration" +[ + damage(integer): "damage applied when exploding. Default is 15." : 15 + scale(float): "Scale of deco. Default 1.0." : 1.0 + model(string): "choose model # -- see list." + mass(float): "*optional* - including this overrides the mass value in decoinfo.txt" + frame(integer): "allows you to specify the starting frame for the model." + animseq(integer): "allows you to specify an animation sequence for the model" + x_speed(integer): "speed to rotate along x axis in degrees per second" + y_speed(integer): "speed to rotate along y axis in degrees per second" + z_speed(integer): "speed to rotate along z axis in degrees per second" + alpha(float): "range 0.0-1.0. Only used if TRANSLUCENT is flagged" + spawnname(string): "classname of entity to throw out upon death" + movetype(string): "none, toss, bounce, float, overrides value in e1decoinfo.csv" : "none" +] + + +// +// Weapons (Episode 2) +// +@PointClass base(Weapons) model({ "path": ":models/e2/a_disk.dkm" }) = weapon_discus : "Discus" [] +@PointClass base(Weapons) model({ "path": ":models/e2/a_venom.dkm" }) = weapon_venomous : "Venomous" [] +@PointClass base(Weapons) model({ "path": ":models/e2/a_sflare.dkm" }) = weapon_sunflare : "Sunflare" [] +@PointClass base(Weapons) model({ "path": ":models/e2/a_hammer.dkm" }) = weapon_hammer : "Hades Hammer" [] +@PointClass base(Weapons) model({ "path": ":models/e2/a_tri.dkm" }) = weapon_trident : "Trident" [] +@PointClass base(Weapons) model({ "path": ":models/e2/a_zeus.dkm" }) = weapon_zeus : "Eye of Zeus" [] + + +// +// Ammo (Episode 2) +// +@PointClass base(Ammo) model({ "path": ":models/e2/wa_trident.dkm" }) = ammo_tritips : "30 trident tips." [] +@PointClass base(Ammo) model({ "path": ":models/e2/wa_venom.dkm" }) = ammo_venomous : "25 cobra venom for Venomous." [] +@PointClass base(Ammo) model({ "path": ":models/e2/wa_zeus.dkm" }) = ammo_zeus : "1 mystic eye for Zeus." [] diff --git a/tools/trenchbroom/games/Daikatana/Episode 3.fgd b/tools/trenchbroom/games/Daikatana/Episode 3.fgd new file mode 100644 index 0000000..051773f --- /dev/null +++ b/tools/trenchbroom/games/Daikatana/Episode 3.fgd @@ -0,0 +1,106 @@ +// +// Daikatana game definition file (.fgd) +// Episode 3 entities +// for Trenchbroom +// last update: 6 Oct, 2018 +// Version: 1 +// +// written by Dekonega +// email me with improvements and suggestions +// + +@include "Common.fgd" + + +// +// Items (Episode 3) +// +@PointClass base(Appearflags, Sidekickflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e3/a3_ar2.dkm" }) = item_black_adamant_armor : "Black adamant armor" [] +@PointClass base(Appearflags, Sidekickflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e3/a3_ar1.dkm" }) = item_chainmail_armor : "Chainmail armor" [] +@PointClass base(Appearflags, KeyFlags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e3/a_tri.dkm" }) = item_trigon_keystone : "Trigon keystone" [] +@PointClass base(Appearflags, KeyFlags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e3/a_quad.dkm" }) = item_quad_keystone : "Quad keystone" [] +@PointClass base(Appearflags, KeyFlags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e3/a_hex.dkm" }) = item_hex_keystone : "Hex keystone" [] +@PointClass base(Appearflags, Sidekickflags, KeyFlags) color(0 0.5 0.8) size(-16 -16 0, 16 16 40) model({ "path": "models/e3/a3_bookw.dkm" }) = item_spellbook : "E3 Wyndrax spell book" [] +@PointClass base(Appearflags, KeyFlags) color(0 0.5 0.8) size(-16 -16 0, 16 16 40) model({ "path": "models/e3/a3_ltkey.dkm" }) = item_wyndrax_key : "E3 wyndrax key" [] +@PointClass base(Appearflags, KeyFlags) color(0 0.5 0.8) size(-16 -16 0, 16 16 40) model({ "path": "models/e3/a3_crkey.dkm" }) = item_crypt_key : "E3 crypt key" [] +@PointClass base(Appearflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e3/a_ringlig.dkm" }) = item_ring_of_lightning : "Ring of lightning" [] +@PointClass base(Appearflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e3/a_ringund.dkm" }) = item_ring_of_undead : "Ring of undead" [] +@PointClass base(Appearflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e3/a_ring_fire.dkm" }) = item_ring_of_fire : "Ring of fire" [] +@PointClass base(Appearflags) color(0 0.5 0.8) size(-16 -16 0, 16 16 32) model({ "path": "models/e3/a_chest.dkm" }) = item_wood_chest : "Wooden chest" [] +@PointClass base(Appearflags, Sidekickflags) color(0 0.5 0.8) size(-16 -16 0, 16 16 32) model({ "path": "models/e3/a_blackchest.dkm" }) = item_black_chest : "Black chest" [] +@PointClass base(Appearflags, PurifierShard) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e3/purifier_3.dkm" }) = item_purifier_shard3 : "Purifier shard 3" [] +@PointClass base(Appearflags, PurifierShard) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e3/purifier_2.dkm" }) = item_purifier_shard2_5 : "Purifier shard 2.5" [] +@PointClass base(Appearflags, PurifierShard) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e3/purifier_2.dkm" }) = item_purifier_shard2_4 : "Purifier shard 2.4" [] +@PointClass base(Appearflags, PurifierShard) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e3/purifier_2.dkm" }) = item_purifier_shard2_3 : "Purifier shard 2.3" [] +@PointClass base(Appearflags, PurifierShard) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e3/purifier_2.dkm" }) = item_purifier_shard2_2 : "Purifier shard 2.2" [] +@PointClass base(Appearflags, PurifierShard) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e3/purifier_2.dkm" }) = item_purifier_shard2_1 : "Purifier shard 2.1" [] +@PointClass base(Appearflags, PurifierShard) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e3/purifier_1.dkm" }) = item_purifier_shard1 : "Purifier shard 1" [] + + +// +// Monsters (Episode 3) +// +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 36) model({ "path": "models/e3/m_wyndrax.dkm" }) = monster_wyndrax : "Wyndrax" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-20 -20 -24, 20 20 40) model({ "path": "models/e3/m_stavros.dkm" }) = monster_stavros : "Stavros" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-20 -20 -24, 20 20 36) model({ "path": "models/e3/m_nharre.dkm" }) = monster_nharre : "Nharre" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e3/m_knight2.dkm" }) = monster_knight2 : "Blue Knight" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e3/m_knight1.dkm" }) = monster_knight1 : "Red Knight" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-20 -20 -24, 20 20 40) model({ "path": "models/e3/m_gharroth.dkm" }) = monster_garroth : "King Gharroth" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-40 -40 -24, 40 40 96) model({ "path": "models/e3/m_dragon.dkm" }) = monster_dragon : "Dragon" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-20 -20 -24, 20 20 16) model({ "path": "models/e3/m_dwarf.dkm" }) = monster_dwarf : "Dwarf" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 40) model({ "path": "models/e3/m_fletcher.dkm" }) = monster_fletcher : "Fletcher" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-20 -20 -24, 20 20 32) model({ "path": "models/e3/m_lycanthir.dkm" }) = monster_lycanthir : "Lycanthir" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-12 -12 -8, 12 12 8) model({ "path": "models/e3/m_doombat.dkm" }) = monster_doombat : "Doombat" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 56) model({ "path": "models/e3/m_priest.dkm" }) = monster_priest : "Priest" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e3/m_buboid.dkm" }) = monster_buboid : "Buboid" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-12 -12 -8, 12 12 8) model({ "path": "models/e3/m_rotworm.dkm" }) = monster_rotworm : "Rotworm" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -16, 16 16 8) model({ "path": "models/e3/m_prat.dkm" }) = monster_plague_rat : "Plague Rat - I broke you!" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-8 -8 -8, 8 8 8) model({ "path": "models/global/e_sflblue.sp2" }) = monster_wisp : "Wisp" +[ + count(integer): "Number of wisps(Max=10)" + distance(integer): "How far the wisps will fly from point of placement(Max=200)" + velocity(integer): "How fast the wisps will move(Max=200)" + scale(float): "How big the wisps will be(1 = normal, 0.5 = half, 2 = twice as big)" + delta_alpha(integer): "frequency of Alpha blending change(0-100%) where 0% means no change" + alpha_level(integer): "Initial Setting for Alpha blending change(1-100%)" +] + + +// +// Decorations (Episode 3) +// +@PointClass base(Appearflags, DecorationFlags) color(1 0 0) size(-8 -8 -32, 8 8 32) = deco_e3 : "Episode 3 decoration" +[ + damage(integer): "damage applied when exploding. Default is 15." : 15 + scale(float): "Scale of deco. Default 1.0." : 1.0 + model(string): "choose model # -- see list." + mass(float): "*optional* - including this overrides the mass value in decoinfo.txt" + frame(integer): "allows you to specify the starting frame for the model." + animseq(integer): "allows you to specify an animation sequence for the model" + x_speed(integer): "speed to rotate along x axis in degrees per second" + y_speed(integer): "speed to rotate along y axis in degrees per second" + z_speed(integer): "speed to rotate along z axis in degrees per second" + alpha(float): "range 0.0-1.0. Only used if TRANSLUCENT is flagged" + spawnname(string): "classname of entity to throw out upon death" + movetype(string): "none, toss, bounce, float, overrides value in e1decoinfo.csv" : "none" +] + + +// +// Weapons (Episode 3) +// +@PointClass base(Weapons) model({ "path": ":models/e3/a_claw.dkm" }) = weapon_silverclaw : "Silverclaw" [] +@PointClass base(Weapons) model({ "path": ":models/e3/a_bolter.dkm" }) = weapon_bolter : "Bolter" [] +@PointClass base(Weapons) model({ "path": ":models/e3/a_bal.dkm" }) = weapon_ballista : "Ballista" [] +@PointClass base(Weapons) model({ "path": ":models/e3/a_stav.dkm" }) = weapon_stavros : "Stave of Stavros" [] +@PointClass base(Weapons) model({ "path": ":models/e3/a_wyndrx.dkm" }) = weapon_wyndrax : "Wyndrax's Wisp" [] +@PointClass base(Weapons) model({ "path": ":models/e3/a_nmare.dkm" }) = weapon_nightmare : "Nharre's Nightmare" [] + + +// +// Ammo (Episode 3) +// +@PointClass base(Ammo) model({ "path": ":models/e3/wa_bolt.dkm" }) = ammo_bolts : "50 crossbow bolts." [] +@PointClass base(Ammo) model({ "path": ":models/e3/wa_stav.dkm" }) = ammo_stavros : "2 lava rocks." [] +@PointClass base(Ammo) model({ "path": ":models/e3/wa_bal.dkm" }) = ammo_ballista : "10 Ballista logs." [] +@PointClass base(Ammo) model({ "path": ":models/e3/we_wisp.dkm" }) = ammo_wisp : "Wyndrax ammo." [] diff --git a/tools/trenchbroom/games/Daikatana/Episode 4.fgd b/tools/trenchbroom/games/Daikatana/Episode 4.fgd new file mode 100644 index 0000000..618bf9f --- /dev/null +++ b/tools/trenchbroom/games/Daikatana/Episode 4.fgd @@ -0,0 +1,86 @@ +// +// Daikatana game definition file (.fgd) +// Episode 4 entities +// for Trenchbroom +// last update: 6 Oct, 2018 +// Version: 1 +// +// written by Dekonega +// email me with improvements and suggestions +// + +@include "Common.fgd" + + +// +// Items (Episode 4) +// +@PointClass base(Appearflags, Sidekickflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e4/a4_ar2.dkm" }) = item_ebonite_armor : "Ebonite armor" [] +@PointClass base(Appearflags, Sidekickflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e4/a4_ar1.dkm" }) = item_kevlar_armor : "Kevlar armor" [] +@PointClass base(Appearflags, KeyFlags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e4/a4_clcgr.dkm" }) = item_control_card_green : "Green control card" [] +@PointClass base(Appearflags, KeyFlags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e4/a4_clcyl.dkm" }) = item_control_card_yellow : "Yellow control card" [] +@PointClass base(Appearflags, KeyFlags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e4/a4_clcbl.dkm" }) = item_control_card_blue : "Blue control card" [] +@PointClass base(Appearflags) color(0 0.5 0.8) size(-16 -16 -24, 16 16 8) model({ "path": "models/e4/a_saltp.dkm" }) = item_saltpeter : "Saltpeter for e4m1 explosives." [] +@PointClass base(Appearflags) color(0 0.5 0.8) size(-16 -16 -24, 16 16 8) model({ "path": "models/e4/a_charcoal.dkm" }) = item_charcoal : "Charcoal for e4m1 explosives." [] +@PointClass base(Appearflags) color(0 0.5 0.8) size(-16 -16 -24, 16 16 8) model({ "path": "models/e4/a_sulphur.dkm" }) = item_sulphur : "Sulphur pouch for e4m1 explosives." [] +@PointClass base(Appearflags) color(0 0.5 0.8) size(-16 -16 -24, 16 16 8) model({ "path": "models/e4/a_bottle.dkm" }) = item_bottle : "Bottle for e4m1 explosives." [] +@PointClass base(Appearflags) color(0 0.5 0.8) size(-16 -16 -16, 16 16 16) model({ "path": "models/e4/a_envsuit.dkm" }) = item_envirosuit : "60 seconds of air and protection from harmful liquids." [] + + +// +// Monsters (Episode 4) +// +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e4/m_kage.dkm" }) = monster_kage : "Kage Mishima" [] +@PointClass base(AppearFlags, MonsterFlags) color(1 0.5 0) size(-16 -16 -8, 16 16 16) model({ "path": "models/e4/m_shark.dkm" }) = monster_shark : "Shark" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e4/m_rocketmp.dkm" }) = monster_rocketmp : "Rocket MP" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e4/m_sgirl.dkm" }) = monster_sealgirl : "SEAL Girl" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e4/m_sealcap.dkm" }) = monster_sealcaptain : "SEAL Captain" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e4/m_scomndo.dkm" }) = monster_sealcommando : "SEAL Commando" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-24 -24 -24, 24 24 24) model({ "path": "models/e4/m_labmonkey.dkm" }) = monster_labmonkey : "Lab Monkey" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e4/m_uzi.dkm" }) = monster_uzigang : "Uzi Gang Member" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-20 -20 -24, 20 20 32) model({ "path": "models/e4/m_chgang.dkm" }) = monster_chaingang : "Chaingun Gang Member" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e4/m_rockgang.dkm" }) = monster_rocketdude : "Rocket Dude" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 32) model({ "path": "models/e4/m_femgang.dkm" }) = monster_femgang : "Female Gang Member" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 40) model({ "path": "models/e4/m_wpris.dkm" }) = monster_whiteprisoner : "White prisoner" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-16 -16 -24, 16 16 40) model({ "path": "models/e4/m_bpris.dkm" }) = monster_blackprisoner : "Black prisoner" [] +@PointClass base(Appearflags, MonsterFlags) color(1 0.5 0) size(-8 -8 -16, 8 8 8) model({ "path": "models/e4/m_piperat.dkm" }) = monster_piperat : "Pipe rat - I broke you!" [] + + +// +// Decorations (Episode 4) +// +@PointClass base(Appearflags, DecorationFlags) color(1 0 0) size(-8 -8 -32, 8 8 32) = deco_e4 : "Episode 4 decoration" +[ + damage(integer): "damage applied when exploding. Default is 15." : 15 + scale(float): "Scale of deco. Default 1.0." : 1.0 + model(string): "choose model # -- see list." + mass(float): "*optional* - including this overrides the mass value in decoinfo.txt" + frame(integer): "allows you to specify the starting frame for the model." + animseq(integer): "allows you to specify an animation sequence for the model" + x_speed(integer): "speed to rotate along x axis in degrees per second" + y_speed(integer): "speed to rotate along y axis in degrees per second" + z_speed(integer): "speed to rotate along z axis in degrees per second" + alpha(float): "range 0.0-1.0. Only used if TRANSLUCENT is flagged" + spawnname(string): "classname of entity to throw out upon death" + movetype(string): "none, toss, bounce, float, overrides value in e1decoinfo.csv" : "none" +] + +// +// Weapons (Episode 4) +// +@PointClass base(Weapons) model({ "path": ":models/e4/a_glock.dkm" }) = weapon_glock : "Glock - Glock Pistol of Love"[] +@PointClass base(Weapons) model({ "path": ":models/e4/a_slugger.dkm" }) = weapon_slugger : "Slugger" [] +@PointClass base(Weapons) model({ "path": ":models/e4/a_kcore.dkm" }) = weapon_kineticore : "Kineticore" [] +@PointClass base(Weapons) model({ "path": ":models/e4/a_ripgun.dkm" }) = weapon_ripgun : "Ripgun - Pulse Rifle" [] +@PointClass base(Weapons) model({ "path": ":models/e4/a_nova.dkm" }) = weapon_novabeam : "Novabeam" [] +@PointClass base(Weapons) model({ "path": ":models/e4/a_mmaser.dkm" }) = weapon_metamaser : "Metamaser" [] + +// +// Ammo (Episode 4) +// +@PointClass base(Ammo) model({ "path": ":models/e4/wa_glock.dkm" }) = ammo_bullets : "A loaded magazine for the glock." [] +@PointClass base(Ammo) model({ "path": ":models/e4/wa_rip.dkm" }) = ammo_slugger : "15 slugs." [] +@PointClass base(Ammo) model({ "path": ":models/e4/wa_rip2.dkm" }) = ammo_cordite : "4 cordite grenades." [] +@PointClass base(Ammo) model({ "path": ":models/e4/wa_kcore.dkm" }) = ammo_kineticore : "50 freeze things." [] +@PointClass base(Ammo) model({ "path": ":models/e4/wa_slug.dkm" }) = ammo_ripgun : "50 Rip-Ups (tm)." [] +@PointClass base(Ammo) model({ "path": ":models/e4/wa_nova.dkm" }) = ammo_novabeam : "50 nova cell units." [] diff --git a/tools/trenchbroom/games/Daikatana/GameConfig.cfg b/tools/trenchbroom/games/Daikatana/GameConfig.cfg new file mode 100644 index 0000000..1444eb5 --- /dev/null +++ b/tools/trenchbroom/games/Daikatana/GameConfig.cfg @@ -0,0 +1,332 @@ +{ + "version": 9, + "name": "Daikatana", + "icon": "Icon.png", + "fileformats": [ { "format": "Daikatana" } ], + "filesystem": { + "searchpath": "data", + "packageformat": { "extension": ".pak", "format": "dkpak" } + }, + "materials": { + "root": "textures", + "extensions": [".wal"] + }, + "entities": { + "definitions": [ "Episode 1.fgd", "Episode 2.fgd", "Episode 3.fgd", "Episode 4.fgd" ], + "defaultcolor": "0.6 0.6 0.6 1.0" + }, + "tags": { + "brush": [ + { + "name": "Weather", + "attribs": [ "transparent" ], + "match": "classname", + "pattern": "effect*" + }, + { + "name": "Trigger", + "attribs": [ "transparent" ], + "match": "classname", + "pattern": "trigger*", + "material": "trigger" + } + ], + "brushface": [ + { + "name": "Clip", + "attribs": [ "transparent" ], + "match": "contentflag", + "flags": [ "playerclip", "monsterclip", "NPC clip" ] + }, + { + "name": "Skip", + "attribs": [ "transparent" ], + "match": "surfaceflag", + "flags": [ "skip" ] + }, + { + "name": "Hint", + "attribs": [ "transparent" ], + "match": "surfaceflag", + "flags": [ "hint" ] + }, + { + "name": "Detail", + "match": "contentflag", + "flags": [ "detail" ] + }, + { + "name": "Liquid", + "match": "contentflag", + "flags": [ "lava", "slime", "water" ] + }, + { + "name": "Sound", + "match": "surfaceflag", + "flags": [ "wood", "metal", "stone", "glass", "ice", "snow", "puddle", "sand" ] + } + ] + }, + "faceattribs": { + "surfaceflags": [ + { + "name": "light", + "description": "1 - Emit light from the surface, brightness is specified in the 'value' field" + }, // 1 + { + "name": "fullbright", + "description": "2 - Fullbright" + }, // 2 + { + "name": "sky", + "description": "4 - The surface is sky, the texture will not be drawn, but the background sky box is used instead" + }, // 4 + { + "name": "warp", + "description": "8 - The surface warps (like water textures do)" + }, // 8 + { + "name": "trans33", + "description": "16 - The surface is 33% transparent" + }, // 16 + { + "name": "trans66", + "description": "32 - The surface is 66% transparent" + }, // 32 + { + "name": "flowing", + "description": "64 - The texture wraps in a downward 'flowing' pattern (warp must also be set)" + }, // 64 + { + "name": "nodraw", + "description": "128 - Used for non-fixed-size brush triggers and clip brushes" + }, // 128 + { + "name": "hint", + "description": "256 - Hint" + }, // 256 + { + "name": "skip", + "description": "512 - Skip" + }, // 512 + { + "name": "wood", + "description": "1024 - Wood" + }, // 1024 + { + "name": "metal", + "description": "2048 - Metal" + }, // 2048 + { + "name": "stone", + "description": "4096 - Stone" + }, // 4096 + { + "name": "glass", + "description": "8192 - Glass" + }, // 8192 + { + "name": "ice", + "description": "16384 - Ice" + }, // 16384 + { + "name": "snow", + "description": "32768 - Snow" + }, // 32768 + { + "name": "mirror", + "description": "65536 - Mirror" + }, // 65536 + { + "name": "holy ground", + "description": "131072 - Holy Grond" + }, // 131072 + { + "name": "alphachan", + "description": "262144 - Alphachan" + }, // 262144 + { + "name": "midtexture", + "description": "524288 - Midtexture (Used together with Clear and Nodraw.)" + }, // 524288 + { + "name": "puddle", + "description": "1048576 - Puddle" + }, // 1048576 + { + "name": "water surge", + "description": "2097152 - Water Surge" + }, // 2097152 + { + "name": "big water surge", + "description": "4194304 - Big Water Surge" + }, // 4194304 + { + "name": "bullet light", + "description": "8388608 - Bullet Light" + }, // 8388608 + { + "name": "fog", + "description": "16777216 - Fog" + }, // 16777216 + { + "name": "sand", + "description": "33554432 - Sand" + }, // 33554432 + { + "name": "4000000", + "description": "67108864 - 4000000" + }, // 67108864 + { + "name": "8000000", + "description": "134217728 - 8000000" + }, // 134217728 + { + "name": "10000000", + "description": "268435456 - 10000000" + }, // 268435456 + { + "name": "20000000", + "description": "536870912 - 20000000" + }, // 536870912 + { + "name": "40000000", + "description": "1073741824 - 40000000" + }, // 1073741824 + { + "name": "80000000", + "description": "-2147483648 - 80000000 (Yes, this is a negative value)" + } // 2147483648 + ], + "contentflags": [ + { + "name": "solid", + "description": "1 - Default for all brushes" + }, // 1 + { + "name": "window", + "description": "2 - Brush is a window (not really used)" + }, // 2 + { + "name": "aux", + "description": "4 - Unused by the Dk's engine?" + }, // 4 + { + "name": "lava", + "description": "8 - The brush is lava" + }, // 8 + { + "name": "slime", + "description": "16 - The brush is slime" + }, // 16 + { + "name": "water", + "description": "32 - The brush is water" + }, // 32 + { + "name": "mist", + "description": "64 - The brush is non-solid" + }, // 64 + { + "name": "clear", + "description": "128 - clear" + }, // 128 + { + "name": "notsolid", + "description": "256 - notsolid" + }, // 256 + { + "name": "noshoot", + "description": "512 - noshoot" + }, // 512 + { + "name": "fog", + "description": "1024 - fog" + }, // 1024 + { + "name": "nitro", + "description": "2048 - nitro" + }, // 2048 + { + "name": "1000", + "description": "4096 - 1000" + }, // 4096 + { + "name": "2000", + "description": "8192 - 2000" + }, // 8192 + { + "name": "4000", + "description": "16384 - 4000" + }, // 16384 + { + "name": "8000", + "description": "32768 - 8000" + }, // 32768 + { + "name": "playerclip", + "description": "65536 - Player cannot pass through the brush (other things can)" + }, // 65536 + { + "name": "monsterclip", + "description": "131072 - Monster cannot pass through the brush (player and other things can)" + }, // 131072 + { + "name": "current_0", + "description": "262144 - Brush has a current in direction of 0 degrees" + }, // 262144 + { + "name": "current_90", + "description": "524288 - Brush has a current in direction of 90 degrees" + }, // 524288 + { + "name": "current_180", + "description": "1048576 - Brush has a current in direction of 180 degrees" + }, // 1048576 + { + "name": "current_270", + "description": "2097152 - Brush has a current in direction of 270 degrees" + }, // 2097152 + { + "name": "current_up", + "description": "4194304 - Brush has a current in the up direction" + }, // 4194304 + { + "name": "current_dn", + "description": "8388608 - Brush has a current in the down direction" + }, // 8388608 + { + "name": "origin", + "description": "16777216 - Special brush used for specifying origin of rotation for rotating brushes" + }, // 16777216 + { + "name": "monster", + "description": "33554432 - Purpose unknown" + }, // 33554432 + { + "name": "corpse", + "description": "67108864 - Purpose unknown" + }, // 67108864 + { + "name": "detail", + "description": "134217728 - Detail" + }, // 134217728 + { + "name": "translucent", + "description": "268435456 - Use for opaque water that does not block vis" + }, // 268435456 + { + "name": "ladder", + "description": "536870912 - Brushes with this flag allow a player to move up and down a vertical surface" + }, // 536870912 + { + "name": "NPC clip", + "description": "1073741824" + }, // 1073741824 + { + "name": "80000000", + "description": "-2147483648 - (Yes, this is a negative value)" + } // 2147483648 + ] + } +} diff --git a/tools/trenchbroom/games/Daikatana/Icon.png b/tools/trenchbroom/games/Daikatana/Icon.png new file mode 100644 index 0000000..7e05b77 Binary files /dev/null and b/tools/trenchbroom/games/Daikatana/Icon.png differ diff --git a/tools/trenchbroom/games/Daikatana/colormap.bmp b/tools/trenchbroom/games/Daikatana/colormap.bmp new file mode 100644 index 0000000..51034df Binary files /dev/null and b/tools/trenchbroom/games/Daikatana/colormap.bmp differ diff --git a/tools/trenchbroom/games/Deathwish/Deathwish.fgd b/tools/trenchbroom/games/Deathwish/Deathwish.fgd new file mode 100644 index 0000000..672c9a8 --- /dev/null +++ b/tools/trenchbroom/games/Deathwish/Deathwish.fgd @@ -0,0 +1,8 @@ +@SolidClass = worldspawn : "World entity" [] + +@baseclass size(-16 -16 -24, 16 16 32) color(0 255 0) = PlayerClass [] + +@PointClass base(PlayerClass) = info_player_start : "Player 1 start" [] + +@PointClass base(PlayerClass) = enemy_spawn : "Enemy Spawn position" [] + diff --git a/tools/trenchbroom/games/Deathwish/GameConfig.cfg b/tools/trenchbroom/games/Deathwish/GameConfig.cfg new file mode 100644 index 0000000..ac880ea --- /dev/null +++ b/tools/trenchbroom/games/Deathwish/GameConfig.cfg @@ -0,0 +1,34 @@ +{ + version: 9, + name: "Deathwish", + icon: "Icon.png", + "fileformats": [ + { "format": "Standard", "initialmap": "initial_standard.map" }, + { "format": "Valve", "initialmap": "initial_valve.map" }, + { "format": "Quake2", "initialmap": "initial_quake2.map" } + ], + "filesystem": { + "searchpath": ".", + "packageformat": { "extension": ".pak", "format": "idpak" } + }, + "materials": { + "root": "textures", + "format": { "extensions": [".png"], "format": "image" } + }, + "entities": { + "definitions": [ "Deathwish.fgd" ], + "defaultcolor": "0.6 0.6 0.6 1.0" + }, + "tags": { + "brush": [], + "brushface": [] + }, + "faceattribs": { + "surfaceflags": [], + "contentflags": [], + "defaults": { + "scale": [0.25, 0.25] + } + } +} + diff --git a/tools/trenchbroom/games/Deathwish/Icon.png b/tools/trenchbroom/games/Deathwish/Icon.png new file mode 100644 index 0000000..a41f2ed Binary files /dev/null and b/tools/trenchbroom/games/Deathwish/Icon.png differ diff --git a/tools/trenchbroom/games/Deathwish/ProtoFloor.png b/tools/trenchbroom/games/Deathwish/ProtoFloor.png new file mode 100644 index 0000000..ea6f4b4 Binary files /dev/null and b/tools/trenchbroom/games/Deathwish/ProtoFloor.png differ diff --git a/tools/trenchbroom/games/DigitalPaintball2/GameConfig.cfg b/tools/trenchbroom/games/DigitalPaintball2/GameConfig.cfg new file mode 100644 index 0000000..d38cc83 --- /dev/null +++ b/tools/trenchbroom/games/DigitalPaintball2/GameConfig.cfg @@ -0,0 +1,232 @@ +{ + "version": 9, + "name": "Digital Paint: Paintball 2", + "icon": "Icon.png", + "fileformats": [ + { "format": "Quake2" }, + { "format": "Quake2 (Valve)"} + ], + "filesystem": { + "searchpath": "pball", + "packageformat": { "extension": ".pak", "format": "idpak" } + }, + "materials": { + "root": "textures", + "extensions": [ ".wal", ".jpg", ".png", ".tga" ], + "palette": "pics/colormap.pcx" + }, + "entities": { + "definitions": [ "pball2.fgd" ], + "defaultcolor": "0.6 0.6 0.6 1.0" + }, + "tags": { + "brush": [ + { + "name": "test2", + "attribs": [ "transparent" ], + "match": "classname", + "pattern": "trigger*", + "material": "trigger" + } + ], + "brushface": [ + { + "name": "Trigger", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "trigger" + }, + { + "name": "Clip", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "clip" + }, + { + "name": "Skip", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "skip" + }, + { + "name": "Hint", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "hint*" + }, + { + "name": "glass", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "*glass*" + }, + { + "name": "window", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "*window*" + }, + { + "name": "trans", + "attribs": [ "transparent" ], + "match": "surfaceflag", + "flags": [ "trans33", "trans66" ] + }, + { + "name": "Detail", + "match": "contentflag", + "flags": [ "detail" ] + }, + { + "name": "Liquid", + "match": "contentflag", + "flags": [ "lava", "slime", "water" ] + }, + { + "name": "nodraw", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "hint*" + } + ] + }, + "faceattribs": { + "surfaceflags": [ + { + "name": "light", + "description": "Emit light from the surface, brightness is specified in the 'value' field" + }, + { + "name": "slick", + "description": "The surface is slippery" + }, + { + "name": "sky", + "description": "The surface is sky, the texture will not be drawn, but the background sky box is used instead" + }, + { + "name": "warp", + "description": "The surface warps (like water textures do)" + }, + { + "name": "trans33", + "description": "The surface is 33% transparent" + }, + { + "name": "trans66", + "description": "The surface is 66% transparent" + }, + { + "name": "flowing", + "description": "The texture wraps in a downward 'flowing' pattern (warp must also be set)" + }, + { + "name": "nodraw", + "description": "Used for non-fixed-size brush triggers and clip brushes" + }, + { + "name": "hint", + "description": "Make a primary bsp splitter" + }, + { + "name": "skip", + "description": "Completely ignore, allowing non-closed brushes" + } + ], + "contentflags": [ + { + "name": "solid", + "description": "Default for all brushes" + }, // 1 << 0 + { + "name": "window", + "description": "Brush is a window (not really used)" + }, // 1 << 1 + { + "name": "aux", + "description": "Unused by the engine" + }, // 1 << 2 + { + "name": "lava", + "description": "The brush is lava" + }, // 1 << 3 + { + "name": "slime", + "description": "The brush is slime" + }, // 1 << 4 + { + "name": "water", + "description": "The brush is water" + }, // 1 << 5 + { + "name": "mist", + "description": "The brush is non-solid" + }, // 1 << 6 + { "unused": true }, // 1 << 7 + { "unused": true }, // 1 << 8 + { "unused": true }, // 1 << 9 + { "unused": true }, // 1 << 10 + { "unused": true }, // 1 << 11 + { "unused": true }, // 1 << 12 + { "unused": true }, // 1 << 13 + { "unused": true }, // 1 << 14 + { "unused": true }, // 1 << 15 + { + "name": "playerclip", + "description": "Player cannot pass through the brush (other things can)" + }, // 1 << 16 + { + "name": "monsterclip", + "description": "Monster cannot pass through the brush (player and other things can)" + }, // 1 << 17 + { + "name": "current_0", + "description": "Brush has a current in direction of 0 degrees" + }, // 1 << 18 + { + "name": "current_90", + "description": "Brush has a current in direction of 90 degrees" + }, // 1 << 19 + { + "name": "current_180", + "description": "Brush has a current in direction of 180 degrees" + }, // 1 << 20 + { + "name": "current_270", + "description": "Brush has a current in direction of 270 degrees" + }, // 1 << 21 + { + "name": "current_up", + "description": "Brush has a current in the up direction" + }, // 1 << 22 + { + "name": "current_dn", + "description": "Brush has a current in the down direction" + }, // 1 << 23 + { + "name": "origin", + "description": "Special brush used for specifying origin of rotation for rotating brushes" + }, // 1 << 24 + { + "name": "monster", + "description": "Purpose unknown" + }, // 1 << 25 + { + "name": "corpse", + "description": "Purpose unknown" + }, // 1 << 26 + { + "name": "detail", + "description": "Detail brush" + }, // 1 << 27 + { + "name": "translucent", + "description": "Use for opaque water that does not block vis" + }, // 1 << 28 + { + "name": "ladder", + "description": "Brushes with this flag allow a player to move up and down a vertical surface" + } // 1 << 29 + ] + } +} diff --git a/tools/trenchbroom/games/DigitalPaintball2/Icon.png b/tools/trenchbroom/games/DigitalPaintball2/Icon.png new file mode 100644 index 0000000..5ef1eb9 Binary files /dev/null and b/tools/trenchbroom/games/DigitalPaintball2/Icon.png differ diff --git a/tools/trenchbroom/games/DigitalPaintball2/pball2.fgd b/tools/trenchbroom/games/DigitalPaintball2/pball2.fgd new file mode 100644 index 0000000..ed46ce6 --- /dev/null +++ b/tools/trenchbroom/games/DigitalPaintball2/pball2.fgd @@ -0,0 +1,805 @@ +// Paintball2 Entities - http://www.digitalpaint.org/ +// Ported from pb2ents_b41.c by sort 3/18/2019 +// Merged with original pball2.fgd and added spawnflags. 3/23/2019 +// TB addon changes 20190403 - xaGe + +@baseclass = AppearFlags [ + spawnflags(Flags) = + [ + 256 : "Not in Easy" : 0 + 512 : "Not in Normal" : 0 + 1024 : "Not in Hard" : 0 + 2048 : "Not in Deathmatch" : 0 + ] +] + +@BaseClass = Target +[ + target(string) : "sets the target to a func_areaportal or target_speaker with the same targetname" +] +@BaseClass = TargetName +[ + targetname(string) : "sets the target from a func_button, func_timer, etc. with the same target" +] +@BaseClass = TeamNumber +[ + teamnumber(integer) : "sets the team for the base." +] +@BaseClass = Angle +[ + angle(string) : "sets the direction the entity faces when spawning. 0 = right (East), 90 = up (North), 180 = left (West), 270 = down (South)." +] +@BaseClass base(AppearFlags) = Group +[ + group(string) : "sets a group where randomly spawned guns will be the same" +] + +@SolidClass = worldspawn : "World entity" +[ + gamemode(Flags) = + [ + 1 : "Deathmatch" : 0 + 2 : "Single flag CTF" : 0 + 4 : "CTF" : 0 + 8 : "Siege" : 0 + 16 : "KOTH" : 0 + 64 : "Pong" : 0 + ] + maxteams(choices) : "sets the max number of teams supported in the map" = + [ + 2 : "for two teams" + 3 : "for three teams" + 4 : "for four teams" + ] + team1(choices) : "sets the color for team 1." = + [ + "red" : "red" + "blue" : "blue" + "yellow" : "yellow" + "purple" : "purple" + ] + team2(choices) : "sets the color for team 2." = + [ + "red" : "red" + "blue" : "blue" + "yellow" : "yellow" + "purple" : "purple" + ] + team3(choices) : "sets the color for team 3." = + [ + "red" : "red" + "blue" : "blue" + "yellow" : "yellow" + "purple" : "purple" + ] + team4(choices) : "sets the color for team 4." = + [ + "red" : "red" + "blue" : "blue" + "yellow" : "yellow" + "purple" : "purple" + ] + message(string) : "sets a string while the map is loading." + sky(string) : "sets a sky to your sky brushes - can be one of the following: unit1_, pbsky1, pbsky2, pbsky3, pbsky4, riverscape1, arctic1" + _sun_light(integer) : "arghrad - example: 250" + _sun_surface(integer) : "arghrad - brightness - A single brightness level. The color of the light is derived from the colors of all active suns, or the texture color if no suns are enabled. A value of 1 is special: it makes ArghRad use the surface`s own light value." + //_sun_surface(color255) : "arghrad - red green blue - Three separate brightness values for red, green, and blue lighting (normally not a standard RGB color). If all three values are 1 or less it has special meaning: it is treated like an RGB color:and the surface`s own light value is used." + _sun_color(string) : "arghrad - Sets the color of the sunlight to the specified rgb color value. If _sun_color is not specified, the color of the sky surface textures will be used instead." + _sun_diffuse(integer) : "arghrad - Sets the brightness of the diffused sunlight. This simulates the diffusion of light by atmospheric haze, creating a soft glow around the edges of sunlight shadows." + _sun_diffade(integer) : "arghrad - Scales how quickly the diffuse sunlight fades out over distance. The default distance is about 64 units. Values less than 1 fade slower, increasing the distance. Values greater than 1 fade faster, decreasing the distance. For example: a value of .5 fades half as fast, covering twice the distance, or about 128 units." + +// Worldspawn Sun Aiming +// Like spotlights, there are several different methods available for setting the direction of suns in the Worldspawn. Choose any one of the methods that you prefer. Remember these point in the direction the sunlight is cast, not towards the sun. All suns points straight down by default. + _sun_angle(string) : "arghrad - Sets the sunlight direction by yaw and pitch angles. Yaw goes from 0-360 degrees around the z-axis, like the angle key. Pitch goes from -90 straight down, through 0 horizontal, to 90 straight up. def=0 -90" + _sun_target(string) : "arghrad - targetname: targetname of spotlight`s info_null. Sets the sunlight direction with separate light & info_null entities. Create and aim a spotlight using the traditional qrad3 info_null method. Then set the _sun_target value to the same targetname as the info_null. The sun will now point in the same direction as that spotlight." + _sun_vector(string) : "arghrad - Sets the sunlight direction by direction vector. This is the direction defined by a ray pointing from the origin (0 0 0) to the specified x y z value." + + requiredfiles(string) : "sets paths for additional files required by the map (such as scripts) that do not download by default - is the path to your file. Always use the forward slash. Keep filenames lowercase. Separate different pathes with a space.Example: 'requiredfiles' 'scripts/maps/mymap1.txt scripts/maps/mymap2.txt' for two of your own files" + forcejail(choices) : "forces eliminated players into jail spawns (no observer/ghosts)." = + [ + 0 : "no force jail" + 1 : "force jail" + ] + minclientbuild(integer) : "sets the minimum version a client must have to play the map (useful if you use advanced features)" + _ambient(integer) : "sets a general map ambient." + +] + +@SolidClass base(AppearFlags) = trigger_multiple : "Variable sized repeatable trigger. Must be targeted at one or more entities." +[ + spawnflags(Flags) = + [ + 1 : "Monster" : 0 + 2 : "Not Player" : 0 + 4 : "Triggered" : 0 + ] + target(target_destination) : "sets the target to any other entities with the same targetname" + message(string) : "sets a string to be displayed when triggered" + delay(integer) : "sets a delay before first firing when turned on (0 default)." + wait(integer) : "sets the seconds between triggerings (2 default)." + sounds(choices) : "sets a sound to be played when triggered" = + [ + 1 : "secret" + 2 : "beep beep" + 3 : "large switch" + ] +] + +@SolidClass base(AppearFlags, TeamNumber) = base : "Base trigger. A player must touch this while holding the flag to get points." +[ + count(integer) : "sets a multiplier for the points scored when capturing. Default is 5, so if you want a flag captured at this base to only be worth 1 point, you can set 'count' '.2'" +] + +@SolidClass base(AppearFlags) = hill : "Hill for gamemode KOTH. When a player touches the hill, their team gets points. A flag with no teamnumber is also suggested, so that it's easy to tell if somebody is on the hill (players can also get points by touching the flag itself)." +[ + gamemode(integer) : "sets the gamemode (KOTH only, should always be 16)." +] + +@SolidClass base(AppearFlags, TeamNumber) = func_teamwall : "Wall that exists only when the team has no players." [] + +@SolidClass base(AppearFlags) = func_dsm : "Dynamically Sizing Map entity. Apply this to brushes to seal off/open areas depending on the number of players present." +[ + spawnflags(Flags) = + [ + 1 : "invert_behavior" : 0 : "closes off areas instead of open up when more players are present." + ] + open_pcount_all(integer) : "if # or more players are in the game, the entity will disappear, opening a new path." + close_pcount_all(integer) : "if # or fewer players are present, the entity will reappear and close off the path." +] + +@baseclass base(AppearFlags, TargetName) size(-16 -16 -24, 16 16 32) color(0 255 0) = PlayerClass [] + +@PointClass base(PlayerClass) = info_player_deathmatch : "Player deathmatch start" +[ + teamnumber(integer) : "sets which team's players will spawn at this point. Setting to 0 means any team can spawn here." + givegun(choices) : "sets the type of the weapon the player starts with instead of the pgp" = + [ + "trracer" : "for spawning a Trracer" + "stingray" : "for spawning a Stingray" + "vm68" : "for spawning a VM-68" + "carbine" : "for spawning a 68 Carbine" + "spyder" : "for spawning a Spyder SE" + "autococker" : "for spawning an Autococker" + "automag" : "for spawning an Automag" + "low" : "for randomly spawning a Trracer or Stingray" + "medium" : "for randomly spawning a VM-68, 68 Carbine or Spyder SE" + "high" : "for randomly spawning an Autococker or Automag" + ] + givehopper(choices) : "sets the type of the hopper the player starts with" = + [ + 100 : "for spawning a hopper of 100" + 200 : "for spawning a hopper of 200" + ] + giveammo(choices) : "sets the type of the ammo pack the player starts with" = + [ + "25" : "for spawning an ammo pack of 25" + "50" : "for spawning an ammo pack of 50" + "100" : "for spawning an ammo pack of 100" + "150" : "for spawning an ammo pack of 150" + "200" : "for spawning an ammo pack of 200" + "small" : "for randomly spawning an ammo pack of 25, 50 or 100" + "medium" : "for randomly spawning an ammo pack of 50, 100 or 150" + "large" : "for randomly spawning an ammo pack of 100, 150 or 200" + ] + givebarrel(choices) : "sets the type of the barrel the player starts with" = + [ + "brass" : "for a brass barrel" + "chrome" : "for a chrome barrel" + "steel" : "for a steel barrel" + ] + giveco2(choices) : "sets the type of the co2 tank the player starts with" = + [ + "12g" : "for spawning a co2 tank of 12g" + "7oz" : "for spawning a co2 tank of 7oz" + "12oz" : "for spawning a co2 tank of 12oz" + "20oz" : "for spawning a co2 tank of 20oz" + "small" : "for randomly spawning a co2 tank of 12g or 7oz" + "medium" : "for randomly spawning a co2 tank of 7oz or 12oz" + "large" : "for randomly spawning a co2 tank of 12oz or 20oz" + ] + loadedco2(choices) : "sets the type of the loaded co2 the player starts with" = + [ + "12g" : "for spawning a co2 tank of 12g" + "7oz" : "for spawning a co2 tank of 7oz" + "12oz" : "for spawning a co2 tank of 12oz" + "20oz" : "for spawning a co2 tank of 20oz" + "small" : "for randomly spawning a co2 tank of 12g or 7oz" + "medium" : "for randomly spawning a co2 tank of 7oz or 12oz" + "large" : "for randomly spawning a co2 tank of 12oz or 20oz" + ] + jail(integer) : "set to 1 to make it a jail spawn for eliminated players." +] +@PointClass base(AppearFlags, Angle) size(-8 -8 -8, 8 8 8) studio({ "path" : model, "skin" : skin, "frame" : frame}) = func_model : "Places a model in the map. Not affected by gravity.Example: 'model' 'models/items/ammo/tris.md2' for the plant model seen in several maps (Pay attention of additional files required by the model.) Add 'requiredfiles' '' to the worldspawn if necessary." +[ + model(string) : "sets what model to use - `models/items/ammo/tris.md2` can be the path of available or your added models" + //skin(string) : "sets what skin # to use - example `3` skin selection defaults to `0` of available or your added models" + //frame(string) : "sets what frame # to use - example `2` can be the frame of available or your added models" +] + +@PointClass base(Group) size(-8 -8 6, 8 8 26) studio({{ +type == "paint" -> {"path":"models/items/grenades/paint/ground.md2", "skin": 0}, +type == "smoke" -> {"path":"models/items/grenades/smoke/ground.md2", "skin": 0}, + "models/items/grenades/paint/ground.md2" +}}) = item_pballgrenade : "Spawning spot for grenades. If no type is specified, the grenade will be random." +[ + type(choices) : "set the type of the grenade" = + [ + "paint" : "for a paint grenade" + "smoke" : "for a smoke grenade" + ] + angle(string) : "-1 sets that the grenade will spawn exactly where you placed the entity and not somewhere in the area." + count(integer) : "1 sets that grenades always spawn there in addition to the number of grenades set by the server." +] + +// xaGe +@PointClass base(Group) color(80 80 255) size(-32 -32 -4, 32 32 28) studio({{ +type == "autococker" -> {"path":"models/weapons/g_autoc/tris.md2"}, +type == "automag" -> {"path":"models/weapons/g_autom/tris.md2"}, +type == "carbine" -> {"path":"models/weapons/g_68carbine/tris.md2"}, +type == "high" -> {"path":"models/weapons/g_autoc/tris.md2"}, +type == "low" -> {"path":"models/weapons/g_trrac/tris.md2"}, +type == "medium" -> {"path":"models/weapons/g_vm68/tris.md2"}, +type == "spyder" -> {"path":"models/weapons/g_spyder/tris.md2"}, +type == "stingray" -> {"path":"models/weapons/g_sting/tris.md2"}, +type == "trracer" -> {"path":"models/weapons/g_trrac/tris.md2"}, +type == "vm68" -> {"path":"models/weapons/g_vm68/tris.md2"}, + "models/weapons/g_vm68/tris.md2" +}}) = weapon_pballgun : + + "Spawning spot for guns. If no type is specified, the gun will be random. + + autococker : Spawns an Autococker + automag : Spawns an Automag + carbine : Spawns a 68 Carbine + high : Randomly spawns either an Autococker or Automag + low : Randomly spawns a Trracer or Stingray + medium : Randomly spawns a VM-68, 68 Carbine or Spyder SE + spyder : Spawns a Spyder SE + stingray : Spawns a Stingray + trracer : Spawns a Trracer + vm68 : Spawns a VM-68" + [ + type(choices) : "sets the type of the weapon" = + [ + "autococker" : "for spawning an Autococker" + "automag" : "for spawning an Automag" + "carbine" : "for spawning a 68 Carbine" + "high" : "for randomly spawning an Autococker or Automag" + "low" : "for randomly spawning a Trracer or Stingray" + "medium" : "for randomly spawning a VM-68, 68 Carbine or Spyder SE" + "spyder" : "for spawning a Spyder SE" + "stingray" : "for spawning a Stingray" + "trracer" : "for spawning a Trracer" + "vm68" : "for spawning a VM-68" + ] +] + +@PointClass base(Group) color(200 0 200) size(-8 -8 16, 8 8 32) studio({{ +type == 100 -> {"path":"models/items/hopper/tris.md2", "skin": 0}, +type == 200 -> {"path":"models/items/hopper/tris.md2", "skin": 1}, + "models/items/hopper/tris.md2" +}}) = item_pballhopper : + + "Spawning spot for hoppers. If no type is specified, the hopper will be random." + [ + type(choices) : "sets the type of the hopper" = + [ + 100 : "for spawning a hopper of 100" + 200 : "for spawning a hopper of 200" + ] +] + +@PointClass base(AppearFlags) color(200 128 25) size(-12 -12 0, 12 12 8) studio({{ +type == "25" -> {"path":"models/items/ammo/tris.md2", "skin": 0, "frame": 0}, +type == "50" -> {"path":"models/items/ammo/tris.md2", "skin": 1, "frame": 1}, +type == "100" -> {"path":"models/items/ammo/tris.md2", "skin": 2, "frame": 2}, +type == "150" -> {"path":"models/items/ammo/tris.md2", "skin": 3, "frame": 3}, +type == "200" -> {"path":"models/items/ammo/tris.md2", "skin": 4, "frame": 4}, +type == "small" -> {"path":"models/items/ammo/tris.md2", "skin": 0, "frame": 0}, +type == "medium" -> {"path":"models/items/ammo/tris.md2", "skin": 2, "frame": 2}, +type == "large" -> {"path":"models/items/ammo/tris.md2", "skin": 3, "frame": 3}, + "models/items/ammo/tris.md2" +}}) = item_pballammo : "Spawning spot for ammo. If no type is specified, the ammo will be random." +[ + type(choices) : "sets the type of the ammo pack" = + [ + "25" : "for spawning an ammo pack of 25" + "50" : "for spawning an ammo pack of 50" + "100" : "for spawning an ammo pack of 100" + "150" : "for spawning an ammo pack of 150" + "200" : "for spawning an ammo pack of 200" + "small" : "for randomly spawning an ammo pack of 25, 50 or 100" + "medium" : "for randomly spawning an ammo pack of 50, 100 or 150" + "large" : "for randomly spawning an ammo pack of 100, 150 or 200" + ] +] + +@PointClass base(Group) color(200 0 0) size(-4 -4 12, 4 4 32) studio({{ +type == "12g" -> {"path":"models/items/co2/12g/tris.md2", "skin": 0}, +type == "7oz" -> {"path":"models/items/co2/7oz/tris.md2", "skin": 0}, +type == "12oz" -> {"path":"models/items/co2/12oz/tris.md2", "skin": 0}, +type == "20oz" -> {"path":"models/items/co2/20oz/tris.md2", "skin": 0}, +type == "small" -> {"path":"models/items/co2/12g/tris.md2", "skin": 0}, +type == "medium" -> {"path":"models/items/co2/7oz/tris.md2", "skin": 0}, +type == "large" -> {"path":"models/items/co2/12oz/tris.md2", "skin": 0}, + "models/items/co2/7oz/tris.md2" +}}) = item_pballco2 : "Spawning spot for co2. If no type is specified, the co2 will be random." +[ + type(choices) : "sets the type of the co2 tank" = + [ + "12g" : "for spawning a co2 tank of 12g" + "7oz" : "for spawning a co2 tank of 7oz" + "12oz" : "for spawning a co2 tank of 12oz" + "20oz" : "for spawning a co2 tank of 20oz" + "small" : "for randomly spawning a co2 tank of 12g or 7oz" + "medium" : "for randomly spawning a co2 tank of 7oz or 12oz" + "large" : "for randomly spawning a co2 tank of 12oz or 20oz" + ] +] + +@PointClass base(Group) color(200 200 0) size(-12 -12 24, 12 12 40) studio({{ +type == "brass" -> {"path":"models/items/barrel/tris.md2", "skin": 2}, +type == "chrome" -> {"path":"models/items/barrel/tris.md2", "skin": 1}, +type == "steel" -> {"path":"models/items/barrel/tris.md2", "skin": 0}, + "models/items/barrel/tris.md2" +}}) = item_pballbarrel : "Spawning spot for barrels. If no type is specified, the barrel will be random." +[ + type(choices) : "sets the type of the barrel" = + [ + "brass" : "for a brass barrel" + "chrome" : "for a chrome barrel" + "steel" : "for a steel barrel" + ] +] + + + +@PointClass base(AppearFlags, TeamNumber) color(0 255 255) size(-8 -16 -16, 8 16 48) studio({"path": "models/items/flag/tris.md2"}) = flag : "" +[ + count(integer) : " + 0.2 - for a flag with one point + 0.4 - for a flag with two points + 0.6 - for a flag with three points + 0.8 - for a flag with four points + 1.0 - for a flag with five points + 1.2 - for a flag with six points + 1.4 - for a flag with seven points + 1.6 - for a flag with eight points + 1.8 - for a flag with nine points + 2.0 - for a flag with ten points" +] + + + +@SolidClass = func_group : "Used to group brushes together just for editor convenience." [] + +@SolidClass = func_areaportal : "This is a non-visible object that divides the world into areas that are seperated when this portal is not activated. Usually enclosed in the middle of a door. This can help performance by not rendering areas that are behind closed doors.Must be targeted." [] + +@PointClass base(AppearFlags) color(128 80 0) size(-8 -8 -8, 8 8 8) = path_corner : "Set the direction of func_trains etc. Target it to the next path corner." +[ + targetname(string) : "sets the target from the previous path_corner entity with the same target" + target(string) : "sets the target to the next path_corner entity with the same targetname" +] + +@PointClass base(AppearFlags) color(0 128 0) size(-4 -4 -4, 4 4 4) = info_null : "Used as a positional target for spotlights, etc." +[ + targetname(string) : "sets the target from the light source with the same target" +] + +@PointClass base(AppearFlags) color(0 128 0) size(-4 -4 -4, 4 4 4) = info_notnull : "Used as a positional target jump pads, etc." +[ + targetname(string) : "sets the target from the trigger_push with the same target" +] + +@PointClass base(AppearFlags) color(0 255 0) size(-8 -8 -8, 8 8 8) = light : "Point light with no visible source. Only applies lighting to the world." +[ + light(integer) : "sets the light power (300 default)." + style(integer) : "sets the light style (0 default)." + _color(color255) : "sets the light color (0 default). Example 255 255 255" + target(string) : "sets the target for spotlights to the info_null entity with the same targetname." + _cone(integer) : "sets the size of light for spotlights (10 default)" +//Light Attenuation + _angfade(integer) : "arghrad - Scales how quickly the light fades as the angle-of-incidence decreases (from perpendicular to parallel). Values less than 1 fade slower, so the angle has less affect. Values greater than 1 fade faster, so the angle has more pronounced affect. def = 1 - This AKA _angwait" + _bounce(integer) : "arghrad - 0 (no bounce) or 1 (bounce) default: 1. A value of 0 allows this light entity to be completely excluded from the bounced light calculations." + _cap(integer) : "arghrad - Caps the lighting cast from this light to the specified brightness level. The lighting is calculated normally, then any brighter points are capped off." + _distance(integer) : "arghrad - Sets the maximum distance that light shines from this entity. Behavior varies depending on the light`s _falloff setting: + +-Linear falloff - Smoothly fades out from the light to the specified distance. This overrides the _fade setting. + +-Inverse & inverse-square falloff - Sets a cutoff distance where the light abruptly stops shining." + _fade(integer) : "arghrad - Scales how quickly the light fades over distance. Values less than 1 fade slower, increasing the distance. Values greater than 1 fade faster, decreasing the distance. For example, a value of .5 fades half as fast, shining twice as far. PLEASE Note: This setting only works on lights with linear falloff." + _falloff(string) : "arghrad - Sets the falloff formula for this light entity. A value of 0 sets linear falloff, the default. A value of 2 sets inverse-square falloff, like surface lights. + +A value of 1 sets inverse falloff: lighting = brightness / distance. At 2 units away the light would be 1/2 as bright, at 3 units it's 1/3, etc. This can work very well for visible-sourced point-lights (mine-lights, torches, etc). It's more realistic than linear falloff, but not as `severe` as inverse-square. + +Note: Inverse and inverse-square falloff require much higher brightness values than linear." +] + +@SolidClass base(AppearFlags) color(0 128 200) = func_wall : "This is just a solid wall if not inhibited." +[ + spawnflags(Flags) = + [ + 1 : "trigger_spawn" : 0 : "the wall will not be present until triggered, it will then blink in to existance; it will kill anything that was in it's way." + 2 : "toggle" : 0 : "only valid for TRIGGER_SPAWN walls, this allows the wall to be turned on and off." + 4 : "start_on" : 0 : "only valid for TRIGGER_SPAWN walls, the wall will initially be present." + 8 : "animated" : 0 + 16 : "animated_fast" : 0 + ] +] + +@SolidClass base(AppearFlags) = func_object : "This is solid bmodel that will fall if it's support is removed." +[ + spawnflags(Flags) = + [ + 1 : "trigger_spawn" : 0 : "the wall will not be present until triggered, it will then blink in to existance; it will kill anything that was in it's way." + 2 : "animated" : 0 + 4 : "animated_fast" : 0 + ] +] + +@SolidClass base(AppearFlags) color(0 0 255) = target_character : "Used with target_string (must be on same 'team')" +[ + count(integer) : "sets the position in the string (starts at 1)" +] + +@PointClass base(AppearFlags) color(0 0 255) size(-8 -8 -8, 8 8 8) = target_string : "" [] + +@PointClass base(AppearFlags) color(0 0 255) size(-8 -8 -8, 8 8 8) = func_clock : "Target a target_string with this. The default is to be a time of day clock.TIMER_UP and TIMER_DOWN run for 'count' '#' seconds and the fire 'pathtarget' ''If START_OFF, this entity must be used before it starts." +[ + spawnflags(Flags) = + [ + 1 : "timer_up" : 0 : "run for 'count' '#' seconds and the fire 'pathtarget' '' - can be your own value." + 2 : "timer_down" : 0 : "run for 'count' '#' seconds and the fire 'pathtarget' '' - can be your own value." + 4 : "start_off" : 0 : "If START_OFF, this entity must be used before it starts." + 8 : "multi_use" : 0 + ] + style(choices) : "clock style" = + [ + 0 : "for a style like xx" + 1 : "for a style like xx:xx" + 2 : "for a style like xx:xx:xx" + ] + pathtarget(string) : "see timer_up and timer_down spawnflags." +] + +@PointClass base(AppearFlags) color(255 0 0) size(-32 -32 -24, 32 32 -16) = misc_teleporter : "Touching this will teleport players to the targeted misc_teleporter_dest object." +[ + target(string) : "sets the target to the misc_teleporter_dest entity with the same targetname" +] + +@PointClass base(AppearFlags, Angle) color(255 0 0) size(-32 -32 -24, 32 32 -16) = misc_teleporter_dest : "Players who touched the 'misc_teleporter' will appear here." +[ + targetname(string) : "sets the target from the misc_teleporter entity with the same target" +] + +@PointClass base(AppearFlags) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_temp_entity : "Fire an origin based temp entity event to the clients." +[ + targetname(string) : "sets the target from a func_button, func_timer, etc. with the same target." + style(integer) : "5 - for a yellow explosion\r21 - for a blue explosion\r45 - for a smoke puff\r48 - for a cyllindrical explosion\r51 - for a large and fast spherical explosion\r52 - for a slow and smaller spherical explosion\rOther values may also work, but can also crash the game, so be careful what you use." +] + +@PointClass base(AppearFlags) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_speaker : "Normal sounds play each time the target is used." +[ + targetname(string) : "sets the target from a func_button, func_timer, etc. with the same target" + noise(string) : "sets the .wav file to play - is the path to your file. Example: 'noise' 'world/cricket.wav'" + volume(float) : "sets the volume power - # options can be 0.0 to 1.0." + attenuation(choices) : "volume falloffLooped sounds are allways atten 3 / vol 1, and the use function toggles it on/off.The reliable flag can be set for very important sounds like crucial voiceovers." = + [ + -1 : "for no falloff, send to whole level" + 1 : "for normal fighting sounds" + 2 : "for idle sound level" + 3 : "for ambient sound level (very rapid falloff)" + ] +] + +@PointClass base(AppearFlags) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_changelevel : "Changes level when fired." +[ + map(string) : "sets the level to change to." +] + +@PointClass base(AppearFlags) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_splash : "Creates a particle splash effect when used." +[ + dmg(integer) : "sets a radius damage to inflict at this location when it splashes (useful for lava/sparks)" + count(integer) : "sets how many pixels are in the splash." + sounds(choices) : "sets a style (not a sound)" = + [ + 1 : "for sparks" + 2 : "for blue water" + 3 : "for brown water" + 4 : "for slime" + 5 : "for lava" + 6 : "for blood" + ] +] + +@PointClass base(AppearFlags) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_spawner : "Set target to the type of entity you want spawned.Useful for spawning monsters and gibs in the factory levels.For monsters:Set direction to the facing you want it to have.For gibs:Set direction if you want it moving and speed how fast it should be moving otherwise it will just be dropped." [] + +@PointClass base(AppearFlags) color(0 128 200) size(-8 -8 -8, 8 8 8) = target_laser : "When triggered, fires a laser. You can either set a target or a direction." +[ + spawnflags(Flags) = + [ + 1 : "start_on" : 0 + 2 : "red" : 0 + 4 : "green" : 0 + 8 : "blue" : 0 + 16 : "yellow" : 0 + 32 : "orange" : 0 + 64 : "fat" : 0 + ] +] + +@PointClass base(AppearFlags) color(0 128 200) size(-8 -8 -8, 8 8 8) = target_lightramp : "Makes a light fade in or fade out." +[ + spawnflags(Flags) = + [ + 1 : "toggle" : 0 + ] + targetname(string) : "sets the target from a func_button, func_timer, etc. with the same target." + target(string) : "sets the target to the light source with the same targetname." + speed(integer) : "sets how many seconds the ramping will take." + message(choices) : "sets the starting lightlevel and the ending lightlevel in two letters" = + [ + "az" : "for a light that fades in from dark to light" + "za" : "for a light that fades in from light to dark" + ] +] + +@SolidClass base(AppearFlags) = trigger_once : "Triggers once, then removes itself. Target it with any entity." +[ + spawnflags(Flags) = + [ + 1 : "triggered" : 0 : "sets that this trigger must be triggered before it is live." + ] + target(string) : "sets the target to any other entities with the same targetname." + message(string) : "sets a string to be displayed when triggered." + delay(integer) : "sets a delay before first firing when turned on (0 default)." + sounds(choices) : "sets a sound to be played when triggered" = + [ + 1 : "secret" + 2 : "beep beep" + 3 : "large switch" + ] +] + +@PointClass base(AppearFlags) color(128 128 128) size(-8 -8 -8, 8 8 8) = trigger_relay : "This fixed size trigger cannot be touched, it can only be fired by other events." [] + +@SolidClass base(AppearFlags) = trigger_counter : "Acts as an intermediary for an action that takes multiple inputs.If nomessage is not set, it will print '1 more.. ' etc when triggered and 'sequence complete' when finished.After the counter has been triggered 'count' '#' times (default 2), it will fire all of it's targets and remove itself." +[ + spawnflags(Flags) = + [ + 1 : "nomessage" : 0 : "If nomessage is not set, it will print '1 more.. ' etc when triggered and 'sequence complete' when finished. After the counter has been triggered 'count' '#' times (default 2), it will fire all of it's targets and remove itself." + ] +] + +@PointClass base(AppearFlags) color(128 128 128) size(-8 -8 -8, 8 8 8) = trigger_always : "This trigger will always fire. It is activated by the world." +[ + target(string) : "sets the target to any other entities with the same targetname" +] + +@SolidClass base(AppearFlags) = trigger_push : "Pushes players and grenades so they will hit the targeted info_notnull." +[ + spawnflags(Flags) = + [ + 1 : "push_once" : 0 : "affects all entities (paint, guns, etc)." + 2 : "push_all" : 0 : "causes the trigger_push to be removed after the first touch." + ] + target(string) : "sets the target to the info_notnull entity with the same targetname" +] + +@SolidClass base(AppearFlags) = trigger_hurt : "Any entity that touches this will be hurt." +[ + spawnflags(Flags) = + [ + 1 : "start_off" : 0 : "when the trigger_hurt must be triggered by a func_button, func_timer, etc." + 2 : "toggle" : 0 : "toggles this trigger between enabled and disabled states." + 4 : "silent" : 0 : "supresses playing the sound." + 8 : "no_protection" : 0 : "makes that nothing can stop the damage." + 16 : "slow" : 0 : "changes the damage rate to once per second." + ] + message(string) : "sets a string to be displayed when touched" + dmg(integer) : "sets a damage to inflict when touches (5 default)" +] + +@SolidClass base(AppearFlags) = trigger_gravity : "Changes the touching entities gravity. Unfortunately, this does not work for players." +[ + gravity(integer) : "sets the gravity value (1 default)." +] + +@SolidClass base(AppearFlags) = func_getoutofjail : "Turns an eleminated player into a living player when touched." +[ + noise(string) : "sets the .wav file to play" +] + +@PointClass base(AppearFlags, Angle) color(255 0 0) size(-16 -16 -24, 16 16 40) = info_player_start : "Starting point for single player, which isn't really applicable here. Players will spawn here if there are no info_player_deathmatches." [] + + +@PointClass base(AppearFlags) color(255 0 255) size(-16 -16 -24, 16 16 40) = info_player_intermission : "This is where the camera will be placed at the end of the match when the scoreboard is shown." +[ + angles(string) : "# # # sets the direction (pitch-yaw-roll)" +] + +@BaseClass base(AppearFlags) = Door +[ + spawnflags(Flags) = + [ + 1 : "start_open" : 0 : "the door to moves to its destination when spawned and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors)." + 2 : "x" : 0 : "" + 4 : "crusher" : 0 : "door will not move back if blocked." + 8 : "nomonster" : 0 : "" + 16 : "animated" : 0 : "" + 32 : "toggle" : 0 : "wait in both the start and end states for a trigger event." + 64 : "animated_fast" : 0 : "" + ] + targetname(string) : "sets the target from a func_button, func_timer, etc. with the same target." + target(string) : "sets the target to a func_areaportal or target_speaker with the same targetname." + message(string) : "sets a string to be displayed when triggered" + team(string) : " sets that all doors with the same team value will open if any door of them gets activated." + health(integer) : "1 sets that the door must be shoot open instead of touching it." + angle(string) : "sets the opening direction of the door (0 default; -1 = upwards; -2 = downwards)." + speed(integer) : "sets the movement speed (100 default)." + wait(integer) : "sets the seconds before returning (3 default, -1 = never return)." + lip(integer) : "sets the lip remaining at end of move (8 default)." + dmg(integer) : "sets a damage to inflict when blocked (2 default)." + _minlight(float) : "sets that the door glows - # options can be 0.0 to 1.0." + sounds(choices) : "sound type" = + [ + 1 : "for a silent sound" + 2 : "for a light sound" + 3 : "for a medium sound" + 4 : "for a heavy sound" + ] +] + +@SolidClass base(AppearFlags, Door) = func_door : "Used for a simple door." +[ +] + +@SolidClass base(AppearFlags, Door) = func_door_rotating : "Used for a simple door." +[ + spawnflags(Flags) = + [ + 2 : "reverse" : 0 : "will cause the door to rotate in the opposite direction." + 64 : "x_axis" : 0 : "rotate on the x axis." + 128 : "y_axis" : 0 : "rotate on the y axis." + ] + distance(integer) : "sets the degrees the door will be rotated." +] + +@SolidClass base(AppearFlags) = func_plat : "Plats are always drawn in the extended position, so they will light correctly.If the plat is the target of another trigger or button, it will start out disabled inthe extended position until it is trigger, when it will lower and become a normal plat." +[ + spawnflags(Flags) = + [ + 1 : "plat_low_trigger" : 0 : "" + ] + height(integer) : "sets the height the platform will move up (positive value) or moves down (negative value)." + speed(integer) : "sets movement speed (150 default)." + accel(integer) : "sets the acceleration when the plat starts to move." + decel(integer) : "sets the deceleration when the plat ends to move." + dmg(integer) : "sets a damage to inflict when blocked (2 default)." + _minlight(float) : "sets that the plat glows - # options can be 0.0 to 1.0." + sounds(choices) : "sound type" = + [ + 1 : "for a base fast sound" + 2 : "for a chain slow sound" + ] +] + +@SolidClass base(AppearFlags) = func_rotating : "You need to have an origin brush as part of this entity. The center of that brush will be the point around which it is rotated. It will rotate around the Z axis by default." +[ + spawnflags(Flags) = + [ + 1 : "start_on" : 0 : "will activate the rotation by the world." + 2 : "reverse" : 0 : "will cause the entity to rotate in the opposite direction." + 4 : "x_axis" : 0 : "rotate on the x axis." + 8 : "y_axis" : 0 : "rotate on the y axis." + 16 : "touch_pain" : 0 : "" + 32 : "stop" : 0 : "stop moving instead of pushing entities." + 64 : "animated" : 0 : "" + 128 : "animated_fast" : 0 : "" + ] + speed(integer) : "sets movement speed (100 default)." + dmg(integer) : "sets a damage to inflict when blocked (2 default)." + _minlight(float) : "sets that the rotating brush glows - # options can be 0.0 to 1.0." +] + +@SolidClass base(AppearFlags) = func_water : "Func_water is a moveable water brush. It must be targeted to operate. Use a non-water texture at your own risk." +[ + spawnflags(Flags) = + [ + 1 : "start_open" : 0 : "causes the water to move to its destination when spawned and operate in reverse." + ] + speed(integer) : "sets the movement speed (25 default)." + wait(integer) : "sets the seconds before returning (-1 default, -1 = TOGGLE)." + lip(integer) : "sets the lip remaining at end of move (0 default)." + angle(string) : "sets the opening direction of the water (0 default; -1 = upwards; -2 = downwards)." + sounds(choices) : "sound type" = + [ + 0 : "no sound" + 1 : "for a water sound" + 2 : "for a lava sound" + ] +] + +@SolidClass base(AppearFlags) = func_train : "Trains are moving platforms that players can ride (if toggle is set).The targets origin specifies the min point of the train at each corner (path_corner).The train spawns at the first target it is pointing at.If the train is the target of a button or trigger, it will not begin moving until activated." +[ + spawnflags(Flags) = + [ + 1 : "start_on" : 0 : "will activate the rotation by the world." + 2 : "toggle" : 0 : "will move the standing people with the train." + 4 : "block_stops" : 0 : "will stop the train while blocking (only if no dmg is set)." + ] + target(string) : "sets the target to a path corner with the same targetname." + targetname(string) : "sets the target from a func_button, func_timer, etc. with the same target." + speed(integer) : "sets movement speed (100 default)." + dmg(integer) : "sets a damage to inflict when blocked (2 default)." + _minlight(float) : "sets that the platform glows - # options can be 0.0 to 1.0." +] + +@PointClass base(AppearFlags) color(80 25 160) size(-8 -8 -8, 8 8 8) = trigger_elevator : "Entity to make a func_train behave like an elevator. Place path_corner's at each floor and set the func_button at that floor to target the trigger_elevator and pathtarget the path_corner." +[ + target(string) : "sets the target to the func_train elevator with the same targetname." + targetname(string) : "sets the target from a func_button, func_timer, etc. with the same target." +] + +@PointClass base(AppearFlags) color(80 25 160) size(-8 -8 -8, 8 8 8) = func_timer : "Timer for trigger lots of stuff. Target it with any entity." +[ + spawnflags(Flags) = + [ + 1 : "start_on" : 0 : "will activate the timer by the world." + ] + target(string) : "sets the target to any other entities with the same targetname." + wait(integer) : "sets the base time between triggering all targets (1 default)." + random(integer) : "sets the wait variance, so the basic time between firing is a random time (0 default)." + delay(integer) : "sets a delay before first firing when turned on (0 default)." + pausetime(integer) : "sets an additional delay used only the very first time and only if spawned with START_ON." +] + +@SolidClass base(AppearFlags) = func_conveyor : "Conveyors are stationary brushes that move what's on them.The brush should be have a surface with at least one current content enabled." +[ + spawnflags(Flags) = + [ + 1 : "start_on" : 0 : "" + 2 : "toggle" : 0 : "" + ] + speed(integer) : "sets the movement speed (100 default)." +] + +// TODO - should this have sounds/lip/etc from base(Door)? +@SolidClass base(AppearFlags) = func_door_secret : "A secret door. Slide back and then to the side." +[ + spawnflags(Flags) = + [ + 1 : "always_shoot" : 0 : "the door is shootable even if targeted." + 2 : "1st_left" : 0 : "the 1st move is left of arrow." + 4 : "1st_down" : 0 : "the 1st move is down from arrow." + ] + targetname(string) : "sets the target from a func_button, func_timer, etc. with the same target." + target(string) : "sets the target to a func_areaportal or target_speaker with the same targetname." + message(string) : "sets a string to be displayed when triggered - can be your own value." + health(integer) : "1 sets that the door must be shoot open instead of touching it." + angle(string) : "sets the opening direction of the door (0 default; -1 = upwards; -2 = downwards)." + speed(integer) : "sets the movement speed (100 default)." + wait(integer) : "sets the seconds before returning (5 default, -1 = never return)." + dmg(integer) : "sets a damage to inflict when blocked (2 default)." + _minlight(float) : "sets that the door glows - # options can be 0.0 to 1.0." +] + +@SolidClass base(AppearFlags) = func_button : "When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again." +[ + target(string) : "sets the target to any other entities with the same targetname." + health(integer) : "sets that the button must be killed instead of touched." + angle(string) : "sets the moving direction." + speed(integer) : "sets the movement speed (40 default)." + wait(integer) : "sets the seconds before returning (1 default, -1 = never return)." + lip(integer) : "sets the lip remaining at end of move (4 default)." + delay(integer) : "sets a delay before first firing when turned on (0 default)." + _minlight(float) : "sets that the door glows - # options can be 0.0 to 1.0." + sounds(choices) : "sound type" = + [ + 1 : "for a silent sound" + 2 : "for a steam metal sound" + 3 : "for a wooden clunk sound" + 4 : "for a metallic click sound" + 5 : "for an in-out sound" + ] +] diff --git a/tools/trenchbroom/games/Generic/GameConfig.cfg b/tools/trenchbroom/games/Generic/GameConfig.cfg new file mode 100644 index 0000000..d47acc5 --- /dev/null +++ b/tools/trenchbroom/games/Generic/GameConfig.cfg @@ -0,0 +1,30 @@ +{ + version: 9, + name: "Generic", + icon: "Icon.png", + "fileformats": [ + { "format": "Standard", "initialmap": "initial_standard.map" }, + { "format": "Valve", "initialmap": "initial_valve.map" }, + { "format": "Quake2", "initialmap": "initial_quake2.map" } + ], + "filesystem": { + "searchpath": ".", + "packageformat": { "extension": ".pak", "format": "idpak" } + }, + "materials": { + "root": "textures", + "format": { "extensions": [".jpg", ".jpeg", ".tga", ".png"], "format": "image" } + }, + "entities": { + "definitions": [ "Generic.fgd" ], + "defaultcolor": "0.6 0.6 0.6 1.0" + }, + "tags": { + "brush": [], + "brushface": [] + }, + "faceattribs": { + "surfaceflags": [], + "contentflags": [] + } +} diff --git a/tools/trenchbroom/games/Generic/Generic.fgd b/tools/trenchbroom/games/Generic/Generic.fgd new file mode 100644 index 0000000..2bebc1c --- /dev/null +++ b/tools/trenchbroom/games/Generic/Generic.fgd @@ -0,0 +1,5 @@ +@SolidClass = worldspawn : "World entity" [] + +@baseclass size(-16 -16 -24, 16 16 32) color(0 255 0) = PlayerClass [] + +@PointClass base(PlayerClass) = info_player_start : "Player 1 start" [] diff --git a/tools/trenchbroom/games/Generic/Icon.png b/tools/trenchbroom/games/Generic/Icon.png new file mode 100644 index 0000000..b1f0d67 Binary files /dev/null and b/tools/trenchbroom/games/Generic/Icon.png differ diff --git a/tools/trenchbroom/games/Halflife/GameConfig.cfg b/tools/trenchbroom/games/Halflife/GameConfig.cfg new file mode 100644 index 0000000..42e657b --- /dev/null +++ b/tools/trenchbroom/games/Halflife/GameConfig.cfg @@ -0,0 +1,79 @@ +{ + "version": 9, + "name": "Half-Life", + "experimental": true, + "icon": "Icon.png", + "fileformats": [ + { "format": "Valve" }, + { "format": "Standard" } + ], + "filesystem": { + "searchpath": "valve", + "packageformat": { "extension": ".pak", "format": "idpak" } + }, + "materials": { + "root": "textures", + "extensions": [".C"], + "palette": "gfx/palette.lmp", + "attribute": "wad" + }, + "entities": { + "definitions": [ "HalfLife.fgd" ], + "defaultcolor": "0.6 0.6 0.6 1.0", + "setDefaultProperties": true + }, + "tags": { + "brush": [ + { + "name": "Trigger", + "attribs": [ "transparent" ], + "match": "classname", + "pattern": "trigger*" + } + ], + "brushface": [ + { + "name": "Clip", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "clip" + }, + { + "name": "Skip", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "skip" + }, + { + "name": "Hint", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "hint*" + }, + { + "name": "Origin", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "origin" + }, + { + "name": "Null", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "null" + }, + { + "name": "Liquid", + "match": "material", + "pattern": "\**" + } + ] + }, + "softMapBounds":"-4096 -4096 -4096 4096 4096 4096", + "compilationTools": [ + { "name": "csg", "description": "Path to your directory containing your CSG tool. ${csg}." }, + { "name": "bsp", "description": "Path to your directory containing your BSP tool. ${bsp}." }, + { "name": "vis", "description": "Path to your directory containing your VIS tool. ${vis}" }, + { "name": "rad", "description": "Path to your directory containing your RAD tool. ${rad}" } + ] +} diff --git a/tools/trenchbroom/games/Halflife/HalfLife.fgd b/tools/trenchbroom/games/Halflife/HalfLife.fgd new file mode 100644 index 0000000..381290b --- /dev/null +++ b/tools/trenchbroom/games/Halflife/HalfLife.fgd @@ -0,0 +1,2717 @@ +// +// Half-Life game definition file (.fgd) +// version 3.0.0.1 +// for Worldcraft 3.3 and above, and Half-Life 1.0.0.9 and above +// +// updated by Chris Bokitch +// autolycus@valvesoftware.com +// http://www.valve-erc.com/ +// + +// +// apr 15 2003 - 3.1.0.0 +// - updated with studio() references to enable model display +// in 3D view +// +// +// aug 28 2001 - 3.0.0.1 +// - changed IS NOT LOOPED to NOT TOGGLED on ambient_generic (royalef) +// - gave light_environment a Name +// - added Angular Velocity to func_train +// - added cycler_wreckage (Waldo) +// - created ZHLT_point baseclass +// - added ZHLT_point base to light, light_environment, and light_spot +// - created ZHLT baseclass +// - added ZHLT base to all applicable brush entities +// - above list compiled by Unquenque +// ------------------------------------------------------------------------ + +// +// worldspawn +// + +@SolidClass = worldspawn : "World entity" +[ + message(string) : "Map Description / Title" + skyname(string) : "environment map (cl_skyname)" + sounds(integer) : "CD track to play" : 1 + light(integer) : "Default light level" + WaveHeight(string) : "Default Wave Height" + MaxRange(string) : "Max viewable distance" : "4096" + chaptertitle(string) : "Chapter Title Message" + startdark(choices) : "Level Fade In" : 0 = + [ + 0 : "No" + 1 : "Yes" + ] + gametitle(choices) : "Display game title" : 0 = + [ + 0 : "No" + 1 : "Yes" + ] + newunit(choices) : "New Level Unit" : 0 = + [ + 0 : "No, keep current" + 1 : "Yes, clear previous levels" + ] + mapteams(string) : "Map Team List" + defaultteam(choices) : "Default Team" : 0 = + [ + 0 : "Fewest Players" + 1 : "First Team" + ] +] + +// +// BaseClasses +// + + +@BaseClass = Sequence +[ + sequence(integer) : "Animation Sequence (editor)" +] + +@BaseClass = ZHLT +[ + zhlt_lightflags(choices) : "ZHLT Lightflags" : 0 = + [ + 0 : "Default" + 1 : "Embedded Fix" + 2 : "Opaque (blocks light)" + 3 : "Opaque + Embedded fix" + 6 : "Opaque + Concave Fix" + ] + light_origin(string) : "Light Origin Target" +] + +@BaseClass = ZHLT_point +[ + _fade(string) : "ZHLT Fade" : "1.0" + _falloff(choices) : "ZHLT Falloff" : 0 = + [ + 0 : "Default" + 1 : "Inverse Linear" + 2 : "Inverse Square" + ] +] + +@BaseClass = Appearflags +[ + spawnflags(Flags) = + [ + 2048 : "Not in Deathmatch" : 0 + ] +] + +@BaseClass = Angles +[ + angles(string) : "Pitch Yaw Roll (Y Z X)" : "0 0 0" +] + +@BaseClass size(0 0 0, 32 32 32) color(80 0 200) base(Appearflags) = Ammo [] + +@BaseClass = Targetname +[ + targetname(target_source) : "Name" +] +@BaseClass = Target +[ + target(target_destination) : "Target" +] +@BaseClass size(-16 -16 0, 16 16 32) color(0 0 200) base(Targetname, Appearflags, Angles) = Weapon [] +@BaseClass = Global +[ + globalname(string) : "Global Entity Name" +] + +@BaseClass base(Target) = Targetx +[ + delay(string) : "Delay before trigger" : "0" + killtarget(target_destination) : "KillTarget" +] + +@BaseClass = RenderFxChoices +[ + renderfx(choices) :"Render FX" : 0 = + [ + 0: "Normal" + 1: "Slow Pulse" + 2: "Fast Pulse" + 3: "Slow Wide Pulse" + 4: "Fast Wide Pulse" + 9: "Slow Strobe" + 10: "Fast Strobe" + 11: "Faster Strobe" + 12: "Slow Flicker" + 13: "Fast Flicker" + 5: "Slow Fade Away" + 6: "Fast Fade Away" + 7: "Slow Become Solid" + 8: "Fast Become Solid" + 14: "Constant Glow" + 15: "Distort" + 16: "Hologram (Distort + fade)" + ] +] + +@BaseClass base(RenderFxChoices) = RenderFields +[ + rendermode(choices) : "Render Mode" : 0 = + [ + 0: "Normal" + 1: "Color" + 2: "Texture" + 3: "Glow" + 4: "Solid" + 5: "Additive" + ] + renderamt(integer) : "FX Amount (1 - 255)" + rendercolor(color255) : "FX Color (R G B)" : "0 0 0" +] + +@BaseClass base(Appearflags, Angles) size(-16 -16 -36, 16 16 36) color(0 255 0) = PlayerClass [] + +@BaseClass base(Target, Targetname, RenderFields, Angles) color(0 200 200) = Monster +[ + TriggerTarget(String) : "TriggerTarget" + TriggerCondition(Choices) : "Trigger Condition" : 0 = + [ + 0 : "No Trigger" + 1 : "See Player, Mad at Player" + 2 : "Take Damage" + 3 : "50% Health Remaining" + 4 : "Death" + 7 : "Hear World" + 8 : "Hear Player" + 9 : "Hear Combat" + 10: "See Player Unconditional" + 11: "See Player, Not In Combat" + ] + spawnflags(Flags) = + [ + 1 : "WaitTillSeen" : 0 + 2 : "Gag" : 0 + 4 : "MonsterClip" : 0 + 16: "Prisoner" : 0 + 128: "WaitForScript" : 0 + 256: "Pre-Disaster" : 0 + 512: "Fade Corpse" : 0 + ] +] + +@BaseClass = TalkMonster +[ + UseSentence(String) : "Use Sentence" + UnUseSentence(String) : "Un-Use Sentence" +] + +@BaseClass base(Targetname, Angles) size(-16 -16 -16, 16 16 16) = gibshooterbase +[ + // how many pieces to create + m_iGibs(integer) : "Number of Gibs" : 3 + + // delay (in seconds) between shots. If 0, all gibs shoot at once. + delay(string) : "Delay between shots" : "0" + + // how fast the gibs are fired + m_flVelocity(integer) : "Gib Velocity" : 200 + + // Course variance + m_flVariance(string) : "Course Variance" : "0.15" + + // Time in seconds for gibs to live +/- 5% + m_flGibLife(string) : "Gib Life" : "4" + + spawnflags(Flags) = + [ + 1 : "Repeatable" : 0 + ] +] + +@BaseClass = Light +[ + _light(color255) : "Brightness" : "255 255 128 200" + 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" + ] + pattern(string) : "Custom Appearance" +] + +@BaseClass base(Targetname,Global) = Breakable +[ + target(target_destination) : "Target on break" + health(integer) : "Strength" : 1 + material(choices) :"Material type" : 0 = + [ + 0: "Glass" + 1: "Wood" + 2: "Metal" + 3: "Flesh" + 4: "Cinder Block" + 5: "Ceiling Tile" + 6: "Computer" + 7: "Unbreakable Glass" + 8: "Rocks" + ] + explosion(choices) : "Gibs Direction" : 0 = + [ + 0: "Random" + 1: "Relative to Attack" + ] + delay(string) : "Delay before fire" : "0" + gibmodel(studio) : "Gib Model" : "" + spawnobject(choices) : "Spawn On Break" : 0 = + [ + 0: "Nothing" + 1: "Battery" + 2: "Healthkit" + 3: "9mm Handgun" + 4: "9mm Clip" + 5: "Machine Gun" + 6: "Machine Gun Clip" + 7: "Machine Gun Grenades" + 8: "Shotgun" + 9: "Shotgun Shells" + 10: "Crossbow" + 11: "Crossbow Bolts" + 12: "357" + 13: "357 clip" + 14: "RPG" + 15: "RPG Clip" + 16: "Gauss clip" + 17: "Hand grenade" + 18: "Tripmine" + 19: "Satchel Charge" + 20: "Snark" + 21: "Hornet Gun" + ] + explodemagnitude(integer) : "Explode Magnitude (0=none)" : 0 +] + +@BaseClass base(Appearflags, Targetname, RenderFields, Global, Angles) = Door +[ + killtarget(target_destination) : "KillTarget" + speed(integer) : "Speed" : 100 + master(string) : "Master" + movesnd(choices) : "Move Sound" : 0 = + [ + 0: "No Sound" + 1: "Servo (Sliding)" + 2: "Pneumatic (Sliding)" + 3: "Pneumatic (Rolling)" + 4: "Vacuum" + 5: "Power Hydraulic" + 6: "Large Rollers" + 7: "Track Door" + 8: "Snappy Metal Door" + 9: "Squeaky 1" + 10: "Squeaky 2" + ] + stopsnd(choices) : "Stop Sound" : 0 = + [ + 0: "No Sound" + 1: "Clang with brake" + 2: "Clang reverb" + 3: "Ratchet Stop" + 4: "Chunk" + 5: "Light airbrake" + 6: "Metal Slide Stop" + 7: "Metal Lock Stop" + 8: "Snappy Metal Stop" + ] + wait(integer) : "delay before close, -1 stay open " : 4 + lip(integer) : "Lip" + dmg(integer) : "Damage inflicted when blocked" : 0 + message(string) : "Message if triggered" + target(target_destination) : "Target" + delay(integer) : "Delay before fire" + netname(string) : "Fire on Close" + health(integer) : "Health (shoot open)" : 0 + spawnflags(flags) = + [ + 1 : "Starts Open" : 0 + 4 : "Don't link" : 0 + 8: "Passable" : 0 + 32: "Toggle" : 0 + 256:"Use Only" : 0 + 512: "Monsters Can't" : 0 + ] + // NOTE: must be duplicated in BUTTON + locked_sound(choices) : "Locked Sound" : 0 = + [ + 0: "None" + 2: "Access Denied" + 8: "Small zap" + 10: "Buzz" + 11: "Buzz Off" + 12: "Latch Locked" + ] + unlocked_sound(choices) : "Unlocked Sound" : 0 = + [ + 0: "None" + 1: "Big zap & Warmup" + 3: "Access Granted" + 4: "Quick Combolock" + 5: "Power Deadbolt 1" + 6: "Power Deadbolt 2" + 7: "Plunger" + 8: "Small zap" + 9: "Keycard Sound" + 10: "Buzz" + 13: "Latch Unlocked" + ] + locked_sentence(choices) : "Locked Sentence" : 0 = + [ + 0: "None" + 1: "Gen. Access Denied" + 2: "Security Lockout" + 3: "Blast Door" + 4: "Fire Door" + 5: "Chemical Door" + 6: "Radiation Door" + 7: "Gen. Containment" + 8: "Maintenance Door" + 9: "Broken Shut Door" + ] + unlocked_sentence(choices) : "Unlocked Sentence" : 0 = + [ + 0: "None" + 1: "Gen. Access Granted" + 2: "Security Disengaged" + 3: "Blast Door" + 4: "Fire Door" + 5: "Chemical Door" + 6: "Radiation Door" + 7: "Gen. Containment" + 8: "Maintenance area" + ] + _minlight(string) : "Minimum light level" +] + +@BaseClass base(Targetname, Target, RenderFields, Global, Angles) = BaseTank +[ + spawnflags(flags) = + [ + 1 : "Active" : 0 + 16: "Only Direct" : 0 + 32: "Controllable" : 0 + ] + + // Mainly for use with 1009 team settings (game_team_master) + master(string) : "(Team) Master" + + yawrate(string) : "Yaw rate" : "30" + yawrange(string) : "Yaw range" : "180" + yawtolerance(string) : "Yaw tolerance" : "15" + pitchrate(string) : "Pitch rate" : "0" + pitchrange(string) : "Pitch range" : "0" + pitchtolerance(string) : "Pitch tolerance" : "5" + barrel(string) : "Barrel Length" : "0" + barrely(string) : "Barrel Horizontal" : "0" + barrelz(string) : "Barrel Vertical" : "0" + spritesmoke(string) : "Smoke Sprite" : "" + spriteflash(string) : "Flash Sprite" : "" + spritescale(string) : "Sprite scale" : "1" + rotatesound(sound) : "Rotate Sound" : "" + firerate(string) : "Rate of Fire" : "1" + bullet_damage(string) : "Damage Per Bullet" : "0" + persistence(string) : "Firing persistence" : "1" + firespread(choices) : "Bullet accuracy" : 0 = + [ + 0: "Perfect Shot" + 1: "Small cone" + 2: "Medium cone" + 3: "Large cone" + 4: "Extra-large cone" + ] + minRange(string) : "Minmum target range" : "0" + maxRange(string) : "Maximum target range" : "0" + _minlight(string) : "Minimum light level" +] + +@BaseClass = PlatSounds +[ + movesnd(choices) : "Move Sound" : 0 = + [ + 0: "No Sound" + 1: "big elev 1" + 2: "big elev 2" + 3: "tech elev 1" + 4: "tech elev 2" + 5: "tech elev 3" + 6: "freight elev 1" + 7: "freight elev 2" + 8: "heavy elev" + 9: "rack elev" + 10: "rail elev" + 11: "squeek elev" + 12: "odd elev 1" + 13: "odd elev 2" + ] + stopsnd(choices) : "Stop Sound" : 0 = + [ + 0: "No Sound" + 1: "big elev stop1" + 2: "big elev stop2" + 3: "freight elev stop" + 4: "heavy elev stop" + 5: "rack stop" + 6: "rail stop" + 7: "squeek stop" + 8: "quick stop" + ] + volume(string) : "Sound Volume 0.0 - 1.0" : "0.85" +] + +@BaseClass base(Targetname, RenderFields, Global, PlatSounds) = Trackchange +[ + height(integer) : "Travel altitude" : 0 + spawnflags(flags) = + [ + 1: "Auto Activate train" : 0 + 2: "Relink track" : 0 + 8: "Start at Bottom" : 0 + 16: "Rotate Only" : 0 + 64: "X Axis" : 0 + 128: "Y Axis" : 0 + ] + rotation(integer) : "Spin amount" : 0 + train(target_destination) : "Train to switch" + toptrack(target_destination) : "Top track" + bottomtrack(target_destination) : "Bottom track" + speed(integer) : "Move/Rotate speed" : 0 +] + +@BaseClass base(Target, Targetname) = Trigger +[ + killtarget(target_destination) : "Kill target" + netname(target_destination) : "Target Path" + master(string) : "Master" + sounds(choices) : "Sound style" : 0 = + [ + 0 : "No Sound" + ] + delay(string) : "Delay before trigger" : "0" + message(string) : "Message (set sound too!)" + spawnflags(flags) = + [ + 1: "Monsters" : 0 + 2: "No Clients" : 0 + 4: "Pushables": 0 + ] +] + +// +// Entities +// + +@PointClass base(Targetname, Targetx, Angles) size(-16 -16 0, 16 16 72) color(255 0 255)=aiscripted_sequence:"AI Scripted Sequence" +[ + m_iszEntity(string) : "Target Monster" + m_iszPlay(string) : "Action Animation" : "" + m_flRadius(integer) : "Search Radius" : 512 + m_flRepeat(integer) : "Repeat Rate ms" : 0 + m_fMoveTo(Choices) : "Move to Position" : 0 = + [ + 0 : "No" + 1 : "Walk" + 2 : "Run" + 4 : "Instantaneous" + 5 : "No - Turn to Face" + ] + m_iFinishSchedule(Choices) : "AI Schedule when done" : 0 = + [ + 0 : "Default AI" + 1 : "Ambush" + ] + spawnflags(Flags) = + [ + 4 : "Repeatable" : 0 + 8 : "Leave Corpse" : 0 + ] +] + +@PointClass iconsprite("sprites/speaker.spr") base(Targetname) = ambient_generic : "Universal Ambient" +[ + message(sound) : "WAV Name" + health(integer) : "Volume (10 = loudest)" : 10 + preset(choices) :"Dynamic Presets" : 0 = + [ + 0: "None" + 1: "Huge Machine" + 2: "Big Machine" + 3: "Machine" + 4: "Slow Fade in" + 5: "Fade in" + 6: "Quick Fade in" + 7: "Slow Pulse" + 8: "Pulse" + 9: "Quick pulse" + 10: "Slow Oscillator" + 11: "Oscillator" + 12: "Quick Oscillator" + 13: "Grunge pitch" + 14: "Very low pitch" + 15: "Low pitch" + 16: "High pitch" + 17: "Very high pitch" + 18: "Screaming pitch" + 19: "Oscillate spinup/down" + 20: "Pulse spinup/down" + 21: "Random pitch" + 22: "Random pitch fast" + 23: "Incremental Spinup" + 24: "Alien" + 25: "Bizzare" + 26: "Planet X" + 27: "Haunted" + ] + volstart(integer) : "Start Volume" : 0 + fadein(integer) : "Fade in time (0-100)" : 0 + fadeout(integer) : "Fade out time (0-100)" : 0 + pitch(integer) : "Pitch (> 100 = higher)" : 100 + pitchstart(integer) : "Start Pitch" : 100 + spinup(integer) : "Spin up time (0-100)" : 0 + spindown(integer) : "Spin down time (0-100)" : 0 + lfotype(integer) : "LFO type 0)off 1)sqr 2)tri 3)rnd" : 0 + lforate(integer) : "LFO rate (0-1000)" : 0 + lfomodpitch(integer) : "LFO mod pitch (0-100)" : 0 + lfomodvol(integer) : "LFO mod vol (0-100)" : 0 + cspinup(integer) : "Incremental spinup count" : 0 + spawnflags(flags) = + [ + 1 : "Play Everywhere" : 0 + 2 : "Small Radius" : 0 + 4 : "Medium Radius" : 1 + 8 : "Large Radius" : 0 + 16 : "Start Silent":0 + 32 : "Not Toggled":0 + ] +] + +// +// ammo +// + + +@PointClass base(Weapon, Targetx) model({ "path": "models/w_9mmclip.mdl" }) = ammo_9mmclip : "9mm Pistol Ammo" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_9mmarclip.mdl" }) = ammo_9mmAR : "9mm Assault Rifle Ammo" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_chainammo.mdl" }) = ammo_9mmbox : "box of 200 9mm shells" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_argrenade.mdl" }) = ammo_ARgrenades : "Assault Grenades" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_shotshell.mdl" }) = ammo_buckshot : "Shotgun Ammo" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_357ammobox.mdl" }) = ammo_357 : "357 Ammo" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_rpgammo.mdl" }) = ammo_rpgclip : "RPG Ammo" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_gaussammo.mdl" }) = ammo_gaussclip : "Gauss Gun Ammo" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_crossbow_clip.mdl" }) = ammo_crossbow : "Crossbow Ammo" [] + +@SolidClass base(Target, ZHLT) = button_target : "Target Button" +[ + spawnflags(flags) = + [ + 1: "Use Activates" : 1 + 2: "Start On" : 0 + ] + master(string) : "Master" + renderfx(choices) :"Render FX" : 0 = + [ + 0: "Normal" + 1: "Slow Pulse" + 2: "Fast Pulse" + 3: "Slow Wide Pulse" + 4: "Fast Wide Pulse" + 9: "Slow Strobe" + 10: "Fast Strobe" + 11: "Faster Strobe" + 12: "Slow Flicker" + 13: "Fast Flicker" + 5: "Slow Fade Away" + 6: "Fast Fade Away" + 7: "Slow Become Solid" + 8: "Fast Become Solid" + 14: "Constant Glow" + 15: "Distort" + 16: "Hologram (Distort + fade)" + ] + rendermode(choices) : "Render Mode" : 0 = + [ + 0: "Normal" + 1: "Color" + 2: "Texture" + 3: "Glow" + 4: "Solid" + 5: "Additive" + ] + renderamt(integer) : "FX Amount (1 - 255)" + rendercolor(color255) : "FX Color (R G B)" : "0 0 0" +] + + +// +// cyclers +// + +@PointClass base(Targetname, Angles, Sequence) size(-16 -16 0, 16 16 72) studio() = cycler : "Monster Cycler" +[ + model(studio) : "Model" + renderfx(choices) :"Render FX" : 0 = + [ + 0: "Normal" + 1: "Slow Pulse" + 2: "Fast Pulse" + 3: "Slow Wide Pulse" + 4: "Fast Wide Pulse" + 9: "Slow Strobe" + 10: "Fast Strobe" + 11: "Faster Strobe" + 12: "Slow Flicker" + 13: "Fast Flicker" + 5: "Slow Fade Away" + 6: "Fast Fade Away" + 7: "Slow Become Solid" + 8: "Fast Become Solid" + 14: "Constant Glow" + 15: "Distort" + 16: "Hologram (Distort + fade)" + ] + rendermode(choices) : "Render Mode" : 0 = + [ + 0: "Normal" + 1: "Color" + 2: "Texture" + 3: "Glow" + 4: "Solid" + 5: "Additive" + ] + renderamt(integer) : "FX Amount (1 - 255)" + rendercolor(color255) : "FX Color (R G B)" : "0 0 0" +] + +@PointClass base(Targetname, Angles) sprite() = cycler_sprite : "Sprite Cycler" +[ + model(sprite) : "Sprite" + framerate(integer) : "Frames per second" : 10 + renderfx(choices) :"Render FX" : 0 = + [ + 0: "Normal" + 1: "Slow Pulse" + 2: "Fast Pulse" + 3: "Slow Wide Pulse" + 4: "Fast Wide Pulse" + 9: "Slow Strobe" + 10: "Fast Strobe" + 11: "Faster Strobe" + 12: "Slow Flicker" + 13: "Fast Flicker" + 5: "Slow Fade Away" + 6: "Fast Fade Away" + 7: "Slow Become Solid" + 8: "Fast Become Solid" + 14: "Constant Glow" + 15: "Distort" + 16: "Hologram (Distort + fade)" + ] + rendermode(choices) : "Render Mode" : 0 = + [ + 0: "Normal" + 1: "Color" + 2: "Texture" + 3: "Glow" + 4: "Solid" + 5: "Additive" + ] + renderamt(integer) : "FX Amount (1 - 255)" + rendercolor(color255) : "FX Color (R G B)" : "0 0 0" +] + +@PointClass base(Monster, Sequence) size(-16 -16 -16, 16 16 16) studio() = cycler_weapon : "Weapon Cycler" +[ + model(studio) : "model" +] + +@PointClass sprite() base(Targetname, RenderFields, Angles) size(-4 -4 -4, 4 4 4) = cycler_wreckage : "Wreckage" +[ + framerate(string) : "Framerate" : "10.0" + model(sprite) : "Sprite Name" : "sprites/fire.spr" + scale(string) : "Scale" : "1.0" + spawnflags(flags) = + [ + 32: "Toggle" : 0 + 64: "Start ON" : 0 + ] +] + +// +// Environmental effects +// + +@BaseClass = BeamStartEnd +[ + LightningStart(target_destination) : "Start Entity" + LightningEnd(target_destination) : "Ending Entity" +] +@PointClass base(Targetname, BeamStartEnd, RenderFxChoices) size(-16 -16 -16, 16 16 16) = env_beam : "Energy Beam Effect" +[ + renderamt(integer) : "Brightness (1 - 255)" : 100 + rendercolor(color255) : "Beam Color (R G B)" : "0 0 0" + Radius(integer) : "Radius" : 256 + life(string) : "Life (seconds 0 = infinite)" : "1" + BoltWidth(integer) : "Width of beam (pixels*0.1 0-255)" : 20 + NoiseAmplitude(integer) : "Amount of noise (0-255)" : 0 + texture(sprite) : "Sprite Name" : "sprites/laserbeam.spr" + TextureScroll(integer) : "Texture Scroll Rate (0-100)" : 35 + framerate(integer) : "Frames per 10 seconds" : 0 + framestart(integer) : "Starting Frame" : 0 + StrikeTime(string) : "Strike again time (secs)" : "1" + damage(string) : "Damage / second" : "0" + spawnflags(flags) = + [ + 1 : "Start On" : 0 + 2 : "Toggle" : 0 + 4 : "Random Strike" : 0 + 8 : "Ring" : 0 + 16: "StartSparks" : 0 + 32: "EndSparks" : 0 + 64: "Decal End" : 0 + 128: "Shade Start" : 0 + 256: "Shade End" : 0 + ] +] + +@PointClass base(Targetname, Angles) size(-4 -4 -4, 4 4 4) = env_beverage : "Beverage Dispenser" +[ + health(integer) : "Capacity" : 10 + skin(choices) : "Beverage Type" : 0 = + [ + 0 : "Coca-Cola" + 1 : "Sprite" + 2 : "Diet Coke" + 3 : "Orange" + 4 : "Surge" + 5 : "Moxie" + 6 : "Random" + ] +] + +@PointClass base(Targetname, Angles) size(-16 -16 -16, 16 16 16) color(255 0 0) = env_blood : "Blood Effects" +[ + color(choices) : "Blood Color" : 0 = + [ + 0 : "Red (Human)" + 1 : "Yellow (Alien)" + ] + amount(string) : "Amount of blood (damage to simulate)" : "100" + spawnflags(flags) = + [ + 1: "Random Direction" : 0 + 2: "Blood Stream" : 0 + 4: "On Player" : 0 + 8: "Spray decals" : 0 + ] +] + +@SolidClass base(Targetname) = env_bubbles : "Bubble Volume" +[ + density(integer) : "Bubble density" : 2 + frequency(integer) : "Bubble frequency" : 2 + current(integer) : "Speed of Current" : 0 + spawnflags(Flags) = + [ + 1 : "Start Off" : 0 + ] +] + +@PointClass base(Targetname) size(-16 -16 -16, 16 16 16) = env_explosion : "Explosion" +[ + iMagnitude(Integer) : "Magnitude" : 100 + spawnflags(flags) = + [ + 1: "No Damage" : 0 + 2: "Repeatable" : 0 + 4: "No Fireball" : 0 + 8: "No Smoke" : 0 + 16: "No Decal" : 0 + 32: "No Sparks" : 0 + ] +] + +@PointClass base(Targetname) color(255 255 128) = env_global : "Global State" +[ + globalstate(string) : "Global State to Set" + triggermode(choices) : "Trigger Mode" : 0 = + [ + 0 : "Off" + 1 : "On" + 2 : "Dead" + 3 : "Toggle" + ] + initialstate(choices) : "Initial State" : 0 = + [ + 0 : "Off" + 1 : "On" + 2 : "Dead" + ] + spawnflags(flags) = + [ + 1 : "Set Initial State" : 0 + ] +] + +@PointClass sprite() base(Targetname, RenderFields) size(-4 -4 -4, 4 4 4) color(30 100 0) = env_glow : "Light Glow/Haze" +[ + model(sprite) : "Sprite Name" : "sprites/glow01.spr" + scale(integer) : "Scale" : 1 +] + +@PointClass base(Targetname) = env_fade : "Screen Fade" +[ + spawnflags(flags) = + [ + 1: "Fade From" : 0 + 2: "Modulate" : 0 + 4: "Activator Only" : 0 + ] + duration(string) : "Duration (seconds)" : "2" + holdtime(string) : "Hold Fade (seconds)" : "0" + renderamt(integer) : "Fade Alpha" : 255 + rendercolor(color255) : "Fade Color (R G B)" : "0 0 0" +] + +@PointClass base(Targetname) size(-16 -16 -16, 16 16 16) = env_funnel : "Large Portal Funnel" +[ + spawnflags(flags) = + [ + 1: "Reverse" : 0 + ] +] + +@PointClass base(Targetname, RenderFxChoices, Angles) size(-16 -16 -16, 16 16 16) = env_laser : "Laser Beam Effect" +[ + LaserTarget(target_destination) : "Target of Laser" + renderamt(integer) : "Brightness (1 - 255)" : 100 + rendercolor(color255) : "Beam Color (R G B)" : "0 0 0" + width(integer) : "Width of beam (pixels*0.1 0-255)" : 20 + NoiseAmplitude(integer) : "Amount of noise (0-255)" : 0 + texture(sprite) : "Sprite Name" : "sprites/laserbeam.spr" + EndSprite(sprite) : "End Sprite" : "" + TextureScroll(integer) : "Texture Scroll Rate (0-100)" : 35 + framestart(integer) : "Starting Frame" : 0 + damage(string) : "Damage / second" : "100" + spawnflags(flags) = + [ + 1 : "Start On" : 0 + 16: "StartSparks" : 0 + 32: "EndSparks" : 0 + 64: "Decal End" : 0 + ] +] + +@PointClass base(Targetname, Target) = env_message : "HUD Text Message" +[ + message(string) : "Message Name" + spawnflags(flags) = + [ + 1: "Play Once" : 0 + 2: "All Clients" : 0 + ] + messagesound(sound) : "Sound Effect" + messagevolume(string) : "Volume 0-10" : "10" + messageattenuation(Choices) : "Sound Radius" : 0 = + [ + 0 : "Small Radius" + 1 : "Medium Radius" + 2 : "Large Radius" + 3 : "Play Everywhere" + ] +] + +@PointClass base(Targetname, Target, RenderFields) size(-16 -16 -16, 16 16 16) color(100 100 0) = env_render : "Render Controls" +[ + spawnflags(flags) = + [ + 1: "No Renderfx" : 0 + 2: "No Renderamt" : 0 + 4: "No Rendermode" : 0 + 8: "No Rendercolor" : 0 + ] +] + +@PointClass base(Targetname) = env_shake : "Screen Shake" +[ + spawnflags(flags) = + [ + 1: "GlobalShake" : 0 + ] + amplitude(string) : "Amplitude 0-16" : "4" + radius(string) : "Effect radius" : "500" + duration(string) : "Duration (seconds)" : "1" + frequency(string) : "0.1 = jerk, 255.0 = rumble" : "2.5" +] + +@PointClass base(gibshooterbase, RenderFields) size(-16 -16 -16, 16 16 16) = env_shooter : "Model Shooter" +[ + shootmodel(studio) : "Model or Sprite name" : "" + shootsounds(choices) :"Material Sound" : -1 = + [ + -1: "None" + 0: "Glass" + 1: "Wood" + 2: "Metal" + 3: "Flesh" + 4: "Concrete" + ] + scale(string) : "Gib Sprite Scale" : "" + skin(integer) : "Gib Skin" : 0 +] + +@PointClass iconsprite("sprites/speaker.spr") = env_sound : "DSP Sound" +[ + radius(integer) : "Radius" : 128 + roomtype(Choices) : "Room Type" : 0 = + [ + 0 : "Normal (off)" + 1 : "Generic" + + 2 : "Metal Small" + 3 : "Metal Medium" + 4 : "Metal Large" + + 5 : "Tunnel Small" + 6 : "Tunnel Medium" + 7 : "Tunnel Large" + + 8 : "Chamber Small" + 9 : "Chamber Medium" + 10: "Chamber Large" + + 11: "Bright Small" + 12: "Bright Medium" + 13: "Bright Large" + + 14: "Water 1" + 15: "Water 2" + 16: "Water 3" + + 17: "Concrete Small" + 18: "Concrete Medium" + 19: "Concrete Large" + + 20: "Big 1" + 21: "Big 2" + 22: "Big 3" + + 23: "Cavern Small" + 24: "Cavern Medium" + 25: "Cavern Large" + + 26: "Weirdo 1" + 27: "Weirdo 2" + 28: "Weirdo 3" + ] +] + +@PointClass base(Targetname, Angles) size(-16 -16 -16, 16 16 16) = env_spark : "Spark" +[ + MaxDelay(string) : "Max Delay" : "0" + spawnflags(flags) = + [ + 32: "Toggle" : 0 + 64: "Start ON" : 0 + ] +] + +@PointClass sprite() base(Targetname, RenderFields, Angles) size(-4 -4 -4, 4 4 4) = env_sprite : "Sprite Effect" +[ + framerate(string) : "Framerate" : "10.0" + model(sprite) : "Sprite Name" : "sprites/glow01.spr" + scale(string) : "Scale" : "" + spawnflags(flags) = + [ + 1: "Start on" : 0 + 2: "Play Once" : 0 + ] +] + +@SolidClass base(Breakable, RenderFields, ZHLT) = func_breakable : "Breakable Object" +[ + spawnflags(flags) = + [ + 1 : "Only Trigger" : 0 + 2 : "Touch" : 0 + 4 : "Pressure" : 0 + 256: "Instant Crowbar" : 1 + ] + _minlight(string) : "Minimum light level" +] + +@SolidClass base(Global,Targetname, Target, RenderFields, Angles, ZHLT) = func_button : "Button" +[ + speed(integer) : "Speed" : 5 + health(integer) : "Health (shootable if > 0)" + lip(integer) : "Lip" + master(string) : "Master" + sounds(choices) : "Sounds" : 0 = + [ + 0: "None" + 1: "Big zap & Warmup" + 2: "Access Denied" + 3: "Access Granted" + 4: "Quick Combolock" + 5: "Power Deadbolt 1" + 6: "Power Deadbolt 2" + 7: "Plunger" + 8: "Small zap" + 9: "Keycard Sound" + 10: "Buzz" + 11: "Buzz Off" + 14: "Lightswitch" + ] + wait(integer) : "delay before reset (-1 stay)" : 3 + delay(string) : "Delay before trigger" : "0" + spawnflags(flags) = + [ + 1: "Don't move" : 0 + 32: "Toggle" : 0 + 64: "Sparks" : 0 + 256:"Touch Activates": 0 + ] + locked_sound(choices) : "Locked Sound" : 0 = + [ + 0: "None" + 2: "Access Denied" + 8: "Small zap" + 10: "Buzz" + 11: "Buzz Off" + 12: "Latch Locked" + ] + unlocked_sound(choices) : "Unlocked Sound" : 0 = + [ + 0: "None" + 1: "Big zap & Warmup" + 3: "Access Granted" + 4: "Quick Combolock" + 5: "Power Deadbolt 1" + 6: "Power Deadbolt 2" + 7: "Plunger" + 8: "Small zap" + 9: "Keycard Sound" + 10: "Buzz" + 13: "Latch Unlocked" + 14: "Lightswitch" + ] + locked_sentence(choices) : "Locked Sentence" : 0 = + [ + 0: "None" + 1: "Gen. Access Denied" + 2: "Security Lockout" + 3: "Blast Door" + 4: "Fire Door" + 5: "Chemical Door" + 6: "Radiation Door" + 7: "Gen. Containment" + 8: "Maintenance Door" + 9: "Broken Shut Door" + ] + unlocked_sentence(choices) : "Unlocked Sentence" : 0 = + [ + 0: "None" + 1: "Gen. Access Granted" + 2: "Security Disengaged" + 3: "Blast Door" + 4: "Fire Door" + 5: "Chemical Door" + 6: "Radiation Door" + 7: "Gen. Containment" + 8: "Maintenance area" + ] + _minlight(string) : "Minimum light level" +] + +@SolidClass base(Global,RenderFields, Targetname, Angles, ZHLT) = func_conveyor : "Conveyor Belt" +[ + spawnflags(flags) = + [ + 1 : "No Push" : 0 + 2 : "Not Solid" : 0 + ] + speed(string) : "Conveyor Speed" : "100" + _minlight(string) : "Minimum light level" +] + +@SolidClass base(Door, ZHLT) = func_door : "Basic door" [] + +@SolidClass base(Door, ZHLT) = func_door_rotating : "Rotating door" +[ + spawnflags(flags) = + [ + 2 : "Reverse Dir" : 0 + 16: "One-way" : 0 + 64: "X Axis" : 0 + 128: "Y Axis" : 0 + ] + distance(integer) : "Distance (deg)" : 90 +] + +@SolidClass base(Appearflags, RenderFields, ZHLT) = func_friction : "Surface with a change in friction" +[ + modifier(integer) : "Percentage of standard (0 - 100)" : 15 +] + +@SolidClass base(Targetname, RenderFields, Global, ZHLT) = func_guntarget : "Moving platform" +[ + speed(integer) : "Speed (units per second)" : 100 + target(target_source) : "First stop target" + message(target_source) : "Fire on damage" + health(integer) : "Damage to Take" : 0 + _minlight(string) : "Minimum light level" +] + +@SolidClass base(Global, RenderFields, ZHLT) = func_healthcharger: "Wall health recharger" +[ + // dmdelay(integer) : "Deathmatch recharge delay" : 0 + _minlight(string) : "Minimum light level" +] + +@SolidClass base(Targetname, RenderFields, ZHLT) = func_illusionary : "Fake Wall/Light" +[ + + skin(choices) : "Contents" : -1 = + [ + -1: "Empty" + -7: "Volumetric Light" + ] + _minlight(string) : "Minimum light level" +] + +@SolidClass base(Targetname) = func_ladder : "Ladder" [] + +@SolidClass base(Targetname) = func_monsterclip : "Monster clip brush" [] + +@SolidClass base(Targetname) = func_mortar_field : "Mortar Field" +[ + m_flSpread(integer) : "Spread Radius" : 64 + m_iCount(integer) : "Repeat Count" : 1 + m_fControl(Choices) : "Targeting" : 0 = + [ + 0 : "Random" + 1 : "Activator" + 2 : "Table" + ] + m_iszXController(target_destination) : "X Controller" + m_iszYController(target_destination) : "Y Controller" +] + +@SolidClass base(Global,Appearflags, Targetname, RenderFields, Angles, ZHLT) = func_pendulum : "Swings back and forth" +[ + speed(integer) : "Speed" : 100 + distance(integer) : "Distance (deg)" : 90 + damp(integer) : "Damping (0-1000)" : 0 + dmg(integer) : "Damage inflicted when blocked" : 0 + spawnflags(flags) = + [ + 1: "Start ON" : 0 + 8: "Passable" : 0 + 16: "Auto-return" : 0 + 64: "X Axis" : 0 + 128: "Y Axis" : 0 + ] + _minlight(integer) : "_minlight" +] + +@SolidClass base(Targetname,Global,RenderFields, PlatSounds, ZHLT) = func_plat : "Elevator" +[ + spawnflags(Flags) = + [ + 1: "Toggle" : 0 + ] + height(integer) : "Travel altitude (can be negative)" : 0 + speed(integer) : "Speed" : 50 + _minlight(string) : "Minimum light level" +] + +@SolidClass base(Targetname, Global, RenderFields, PlatSounds, Angles, ZHLT) = func_platrot : "Moving Rotating platform" +[ + spawnflags(Flags) = + [ + 1: "Toggle" : 1 + 64: "X Axis" : 0 + 128: "Y Axis" : 0 + ] + speed(integer) : "Speed of rotation" : 50 + height(integer) : "Travel altitude (can be negative)" : 0 + rotation(integer) : "Spin amount" : 0 + _minlight(string) : "Minimum light level" +] + +@SolidClass base(Breakable, RenderFields, ZHLT) = func_pushable : "Pushable object" +[ + size(choices) : "Hull Size" : 0 = + [ + 0: "Point size" + 1: "Player size" + 2: "Big Size" + 3: "Player duck" + ] + spawnflags(flags) = + [ + 128: "Breakable" : 0 + ] + friction(integer) : "Friction (0-400)" : 50 + buoyancy(integer) : "Buoyancy" : 20 + _minlight(string) : "Minimum light level" +] + +@SolidClass base(Global,RenderFields, ZHLT) = func_recharge: "Battery recharger" +[ + // dmdelay(integer) : "Deathmatch recharge delay" : 0 + _minlight(string) : "Minimum light level" +] + +@SolidClass base(Targetname, Global, RenderFields, Angles, ZHLT) = func_rot_button : "RotatingButton" +[ + target(target_destination) : "Targetted object" + // changetarget will change the button's target's TARGET field to the button's changetarget. + changetarget(target_destination) : "ChangeTarget Name" + master(string) : "Master" + speed(integer) : "Speed" : 50 + health(integer) : "Health (shootable if > 0)" + sounds(choices) : "Sounds" : 21 = + [ + 21: "Squeaky" + 22: "Squeaky Pneumatic" + 23: "Ratchet Groan" + 24: "Clean Ratchet" + 25: "Gas Clunk" + ] + wait(choices) : "Delay before reset" : 3 = + [ + -1: "Stays pressed" + ] + delay(string) : "Delay before trigger" : "0" + distance(integer) : "Distance (deg)" : 90 + spawnflags(flags) = + [ + 1 : "Not solid" : 0 + 2 : "Reverse Dir" : 0 + 32: "Toggle" : 0 + 64: "X Axis" : 0 + 128: "Y Axis" : 0 + 256:"Touch Activates": 0 + ] + _minlight(integer) : "_minlight" +] + +@SolidClass base(Targetname, Global, RenderFields, Angles, ZHLT) = func_rotating : "Rotating Object" +[ + speed(integer) : "Rotation Speed" : 0 + volume(integer) : "Volume (10 = loudest)" : 10 + fanfriction(integer) : "Friction (0 - 100%)" : 20 + sounds(choices) : "Fan Sounds" : 0 = + [ + 0 : "No Sound" + 1 : "Fast Whine" + 2 : "Slow Rush" + 3 : "Medium Rickety" + 4 : "Fast Beating" + 5 : "Slow Smooth" + ] + message(sound) : "WAV Name" + spawnflags(flags) = + [ + 1 : "Start ON" : 0 + 2 : "Reverse Direction" : 0 + 4 : "X Axis" : 0 + 8 : "Y Axis" : 0 + 16: "Acc/Dcc" : 0 + 32: "Fan Pain" : 0 + 64: "Not Solid" : 0 + 128: "Small Radius" : 0 + 256: "Medium Radius" : 0 + 512: "Large Radius" : 1 + ] + _minlight(integer) : "_minlight" + spawnorigin(string) : "X Y Z - Move here after lighting" : "0 0 0" + dmg(integer) : "Damage inflicted when blocked" : 0 +] + +@SolidClass base(BaseTank, ZHLT) = func_tank : "Brush Gun Turret" +[ + bullet(choices) : "Bullets" : 0 = + [ + 0: "None" + 1: "9mm" + 2: "MP5" + 3: "12mm" + ] +] + +@SolidClass = func_tankcontrols : "Tank controls" +[ + target(target_destination) : "Tank entity name" +] + +@SolidClass base(BaseTank, ZHLT) = func_tanklaser : "Brush Laser Turret" +[ + laserentity(target_source) : "env_laser Entity" +] + +@SolidClass base(BaseTank, ZHLT) = func_tankrocket : "Brush Rocket Turret" [] + + +@SolidClass base(BaseTank, ZHLT) = func_tankmortar : "Brush Mortar Turret" +[ + iMagnitude(Integer) : "Explosion Magnitude" : 100 +] + +@SolidClass base(Trackchange, ZHLT) = func_trackautochange : "Automatic track changing platform" +[ + _minlight(string) : "Minimum light level" +] + +@SolidClass base(Trackchange, ZHLT) = func_trackchange : "Train track changing platform" +[ + _minlight(string) : "Minimum light level" +] + +@SolidClass base(Targetname, Global, RenderFields, ZHLT) = func_tracktrain : "Track Train" +[ + spawnflags(flags) = + [ + 1 : "No Pitch (X-rot)" : 0 + 2 : "No User Control" : 0 + 8 : "Passable" : 0 + ] + target(target_destination) : "First stop target" + sounds(choices) : "Sound" : 0 = + [ + 0: "None" + 1: "Rail 1" + 2: "Rail 2" + 3: "Rail 3" + 4: "Rail 4" + 5: "Rail 6" + 6: "Rail 7" + ] + wheels(integer) : "Distance between the wheels" : 50 + height(integer) : "Height above track" : 4 + startspeed(integer) : "Initial speed" : 0 + speed(integer) : "Speed (units per second)" : 64 + dmg(integer) : "Damage on crush" : 0 + volume(integer) : "Volume (10 = loudest)" : 10 + bank(string) : "Bank angle on turns" : "0" + _minlight(string) : "Minimum light level" +] + +@SolidClass = func_traincontrols : "Train Controls" +[ + target(target_destination) : "Train Name" +] + +@SolidClass base(Targetname, Global, RenderFields, ZHLT) = func_train : "Moving platform" +[ + target(target_source) : "First stop target" + movesnd(choices) : "Move Sound" : 0 = + [ + 0: "No Sound" + 1: "big elev 1" + 2: "big elev 2" + 3: "tech elev 1" + 4: "tech elev 2" + 5: "tech elev 3" + 6: "freight elev 1" + 7: "freight elev 2" + 8: "heavy elev" + 9: "rack elev" + 10: "rail elev" + 11: "squeek elev" + 12: "odd elev 1" + 13: "odd elev 2" + ] + stopsnd(choices) : "Stop Sound" : 0 = + [ + 0: "No Sound" + 1: "big elev stop1" + 2: "big elev stop2" + 3: "freight elev stop" + 4: "heavy elev stop" + 5: "rack stop" + 6: "rail stop" + 7: "squeek stop" + 8: "quick stop" + ] + speed(integer) : "Speed (units per second)" : 64 + avelocity(string) : "Angular Veocity (y z x)" + dmg(integer) : "Damage on crush" : 0 + skin(integer) : "Contents" : 0 + volume(string) : "Sound Volume 0.0 - 1.0" : "0.85" + spawnflags(flags) = + [ + 8 : "Not solid" : 0 + ] + _minlight(string) : "Minimum light level" +] + +@SolidClass base(Targetname, Appearflags, RenderFields, Global, ZHLT) = func_wall : "Wall" +[ + _minlight(string) : "Minimum light level" +] + +@SolidClass base(func_wall) = func_wall_toggle : "Toggleable geometry" +[ + spawnflags(flags) = + [ + 1 : "Starts Invisible" : 0 + ] +] + +@SolidClass base(Door, ZHLT) = func_water : "Liquid" +[ + spawnflags(flags) = + [ + 1 : "Starts Open" : 0 + 256:"Use Only" : 0 + ] + skin(choices) : "Contents" : -3 = + [ + -3: "Water" + -4: "Slime" + -5: "Lava" + ] + WaveHeight(string) : "Wave Height" : "3.2" +] + +// +// game entities (requires Half-Life 1.0.0.9) +// + +@PointClass base(Targetname, Targetx) = game_counter : "Fires when it hits limit" +[ + spawnflags(flags) = + [ + 1: "Remove On fire" : 0 + 2: "Reset On fire" : 1 + ] + master(string) : "Master" + frags(integer) : "Initial Value" : 0 + health(integer) : "Limit Value" : 10 +] + +@PointClass base(Targetname, Target) = game_counter_set : "Sets a game_counter" +[ + spawnflags(flags) = + [ + 1: "Remove On fire" : 0 + ] + master(string) : "Master" + frags(integer) : "New Value" : 10 +] + +@PointClass base(Targetname) = game_end : "End this multiplayer game" +[ + master(string) : "Master" +] + +@PointClass base(Targetname) = game_player_equip : "Initial player equipment" +[ + spawnflags(flags) = + [ + 1: "Use Only" : 0 + ] + master(string) : "Team Master" +] + +@PointClass base(Targetname) = game_player_hurt : "Hurts player who fires" +[ + dmg(string) : "Damage To Apply" : "999" + spawnflags(flags) = + [ + 1: "Remove On fire" : 0 + ] + master(string) : "Master" +] + +@PointClass base(Targetname) = game_player_team : "Allows player to change teams" +[ + spawnflags(flags) = + [ + 1 : "Remove On fire" : 0 + 2 : "Kill Player" : 0 + 4 : "Gib Player" : 0 + ] + target(string) : "game_team_master to use" + master(string) : "Master" +] + +@PointClass base(Targetname) = game_score : "Award/Deduct Points" +[ + spawnflags(flags) = + [ + 1: "Allow Negative" : 0 + 2: "Team Points" : 0 + ] + + points(integer) : "Points to add (+/-)" : 1 + master(string) : "Master" +] + +@PointClass base(Targetname, Targetx) = game_team_master : "Team based master/relay" +[ + spawnflags(flags) = + [ + 1: "Remove On fire" : 0 + ] + triggerstate(choices) : "Trigger State" : 0 = + [ + 0: "Off" + 1: "On" + 2: "Toggle" + ] + teamindex(integer) : "Team Index (-1 = no team)" : -1 + master(string) : "Master" +] + +@PointClass base(Targetname, Targetx) = game_team_set : "Sets team of team_master" +[ + spawnflags(flags) = + [ + 1: "Remove On fire" : 0 + ] + master(string) : "Master" +] + +@PointClass base(Targetname, Target) = game_text : "HUD Text Message" +[ + spawnflags(flags) = + [ + 1: "All Players" : 0 + ] + + message(string) : "Message Text" + x(string) : "X (0 - 1.0 = left to right) (-1 centers)" : "-1" + y(string) : "Y (0 - 1.0 = top to bottom) (-1 centers)" : "-1" + effect(Choices) : "Text Effect" : 0 = + [ + 0 : "Fade In/Out" + 1 : "Credits" + 2 : "Scan Out" + ] + color(color255) : "Color1" : "100 100 100" + color2(color255) : "Color2" : "240 110 0" + fadein(string) : "Fade in Time (or character scan time)" : "1.5" + fadeout(string) : "Fade Out Time" : "0.5" + holdtime(string) : "Hold Time" : "1.2" + fxtime(string) : "Scan time (scan effect only)" : "0.25" + channel(choices) : "Text Channel" : 1 = + [ + 1 : "Channel 1" + 2 : "Channel 2" + 3 : "Channel 3" + 4 : "Channel 4" + ] + master(string) : "Master" +] + +@SolidClass base(Targetname) = game_zone_player : "Player Zone brush" +[ + intarget(target_destination) : "Target for IN players" + outtarget(target_destination) : "Target for OUT players" + incount(target_destination) : "Counter for IN players" + outcount(target_destination) : "Counter for OUT players" + // master(string) : "Master" +] + +@PointClass base(gibshooterbase) = gibshooter : "Gib Shooter" [] + +// +// info entities +// + +@PointClass decal() base(Targetname, Appearflags) = infodecal : "Decal" +[ + texture(decal) +] + +@PointClass base(Targetname) size(-24 -24 0, 24 24 16) color(20 190 60) = info_bigmomma : "Big Mamma Node" +[ + spawnflags(Flags) = + [ + 1 : "Run To Node" : 0 + 2 : "Wait Indefinitely" : 0 + ] + target(target_destination) : "Next node" + radius(string) : "Radius" : "0" + reachdelay(string) : "Wait after approach" : "0" + killtarget(target_destination) : "KillTarget" + reachtarget(target_destination) : "Fire on approach" + reachsequence(string) : "Sequence on approach" : "" + health(string) : "Health on approach" : "" + presequence(string) : "Sequence before approach" : "" +] + +@PointClass base(Target, Angles) size(-4 -4 -4, 4 4 4) color(0 255 0) = info_intermission : "Intermission Spot" [] + +@PointClass base(Targetname) = info_landmark : "Transition Landmark" [] + +@PointClass size(-24 -24 -4, 24 24 4) color(255 255 0) = info_node : "ai node" [] + +@PointClass size(-32 -32 0, 32 32 64) color(255 255 0) = info_node_air : "ai air node" [] + +@PointClass base(Targetname) = info_null : "info_null (spotlight target)" [] + +@PointClass base(PlayerClass) = info_player_coop : "Player cooperative start" [] +@PointClass base(PlayerClass, Sequence) model({ "path": "models/player.mdl", "frame": sequence, "skin": skin }) = info_player_deathmatch : "Player deathmatch start" +[ + target(target_destination) : "Target" + master(string) : "Master" +] +@PointClass base(PlayerClass, Sequence) model({ "path": "models/player.mdl", "frame": sequence, "skin": skin }) = info_player_start : "Player 1 start" [] + +@PointClass base(Targetname) size(-4 -4 -4, 4 4 4) color(200 100 50) = info_target : "Beam Target" [] +@PointClass size(-8 -8 0, 8 8 16) base(PlayerClass, Targetname) = info_teleport_destination : "Teleport destination" [] + +// +// items +// + +@PointClass size(-16 -16 0, 16 16 36) base(Weapon, Targetx) model({ "path": "models/w_oxygen.mdl" }) = item_airtank : "Oxygen tank" [] +@PointClass size(-16 -16 0, 16 16 36) base(Weapon, Targetx) model({ "path": "models/w_antidote.mdl" }) = item_antidote : "Poison antidote" [] +@PointClass size(-16 -16 0, 16 16 36) base(Weapon, Targetx) model({ "path": "models/w_battery.mdl" }) = item_battery : "HEV battery" [] +@PointClass size(-16 -16 0, 16 16 36) base(Weapon, Targetx) model({ "path": "models/w_medkit.mdl" }) = item_healthkit : "Small Health Kit" [] +@PointClass size(-16 -16 0, 16 16 36) base(Weapon, Targetx) model({ "path": "models/w_longjump.mdl" }) = item_longjump : "Longjump Module" [] +@PointClass size(-16 -16 0, 16 16 36) base(Weapon, Targetx) model({ "path": "models/w_security.mdl" }) = item_security : "Security card" [] +@PointClass size(-16 -16 0, 16 16 36) base(Weapon, Targetx) model({ "path": "models/w_suit.mdl" }) = item_suit : "HEV Suit" +[ + spawnflags(Flags) = + [ + 1 : "Short Logon" : 0 + ] +] + +// +// lights +// + +@PointClass iconsprite("sprites/lightbulb.spr") base(Target, Targetname, Light, ZHLT_point) = light : "Invisible lightsource" +[ + spawnflags(Flags) = [ 1 : "Initially dark" : 0 ] +] + +@PointClass iconsprite("sprites/lightbulb.spr") base(Targetname, Target, Angles, ZHLT_point) = light_spot : "Spotlight" +[ + _cone(integer) : "Inner (bright) angle" : 30 + _cone2(integer) : "Outer (fading) angle" : 45 + pitch(integer) : "Pitch" : -90 + _light(color255) : "Brightness" : "255 255 128 200" + _sky(Choices) : "Is Sky" : 0 = + [ + 0 : "No" + 1 : "Yes" + ] + spawnflags(Flags) = [ 1 : "Initially dark" : 0 ] + 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" + ] + pattern(string) : "Custom Appearance" +] + +@PointClass base(Targetname, Angles, ZHLT_point) iconsprite("sprites/lightbulb.spr") = light_environment : "Environment" +[ + pitch(integer) : "Pitch" : 0 + _light(color255) : "Brightness" : "255 255 128 200" +] + +@SolidClass base(Door, ZHLT) = momentary_door : "Momentary/Continuous door" +[ + spawnflags(flags) = + [ + 1 : "Starts Open" : 0 + ] +] + +@SolidClass base(Targetname, Target, Angles, RenderFields, ZHLT) = momentary_rot_button : "Direct wheel control" +[ + speed(integer) : "Speed" : 50 + master(string) : "Master" + sounds(choices) : "Sounds" : 0 = + [ + 0: "None" + 1: "Big zap & Warmup" + 2: "Access Denied" + 3: "Access Granted" + 4: "Quick Combolock" + 5: "Power Deadbolt 1" + 6: "Power Deadbolt 2" + 7: "Plunger" + 8: "Small zap" + 9: "Keycard Sound" + 21: "Squeaky" + 22: "Squeaky Pneumatic" + 23: "Ratchet Groan" + 24: "Clean Ratchet" + 25: "Gas Clunk" + ] + distance(integer) : "Distance (deg)" : 90 + returnspeed(integer) : "Auto-return speed" : 0 + spawnflags(flags) = + [ + 1: "Door Hack" : 0 + 2: "Not useable" : 0 + 16: "Auto Return" : 0 + 64: "X Axis" : 0 + 128: "Y Axis" : 0 + ] + _minlight(integer) : "_minlight" +] + +// +// monsters +// + +@PointClass base(Monster, Sequence) size(-16 -16 0, 16 16 72) model({ "path": "models/controller.mdl", "frame": sequence, "skin": skin }) = monster_alien_controller : "Controller" [] +@PointClass base(Monster, Sequence) size(-32 -32 0, 32 32 64) model({ "path": "models/agrunt.mdl", "frame": sequence, "skin": skin }) = monster_alien_grunt : "Alien Grunt" +[ + netname(string) : "Squad Name" + spawnflags(Flags) = + [ + 32 : "SquadLeader" : 0 + ] +] +@PointClass base(Monster, Sequence) size(-16 -16 0, 16 16 72) model({ "path": "models/islave.mdl", "frame": sequence, "skin": skin }) = monster_alien_slave : "Vortigaunt" +[ + netname(string) : "Squad Name" + spawnflags(Flags) = + [ + 32 : "SquadLeader" : 0 + 64 : "IgnorePlayer" : 0 + ] +] +@PointClass base(Monster, Sequence) size(-360 -360 -172, 360 360 8) model({ "path": "models/apache.mdl", "frame": sequence, "skin": skin }) = monster_apache : "Apache" +[ + spawnflags(Flags) = + [ + 8 : "NoWreckage" : 0 + 64 : "Start Inactive" : 0 + ] +] +@PointClass base(Monster, Sequence) size(-16 -16 0, 16 16 36) model({ "path": "models/baby_headcrab.mdl", "frame": sequence, "skin": skin }) = monster_babycrab : "Baby Headcrab" [] +@PointClass base(RenderFields, Sequence) size(-16 -16 -36, 16 16 0) model({ "path": "models/barnacle.mdl", "frame": sequence, "skin": skin }) = monster_barnacle : "Barnacle Monster" [] +@PointClass base(Monster,TalkMonster, Sequence) size(-16 -16 0, 16 16 72) model({ "path": "models/barney.mdl", "frame": sequence, "skin": skin }) = monster_barney : "Barney" [] +@PointClass base(RenderFields,Appearflags, Angles, Sequence) size(-16 -16 0, 16 16 72) = monster_barney_dead : "Dead Barney" +[ + pose(Choices) : "Pose" : 0 = + [ + 0 : "On back" + 1 : "On side" + 2 : "On stomach" + ] +] +@PointClass base(Monster, Sequence) size(-95 -95 0, 95 95 190) model({ "path": "models/big_mom.mdl", "frame": sequence, "skin": skin }) = monster_bigmomma : "Big Mamma" +[ + netname(string) : "First node" : "" +] +@PointClass base(Monster, Sequence) size(-16 -16 0, 16 16 72) model({ "path": "models/floater.mdl", "frame": sequence, "skin": skin }) = monster_bloater : "Bloater" [] +@PointClass base(Monster, Sequence) size(-32 -32 0, 32 32 64) model({ "path": "models/bullsquid.mdl", "frame": sequence, "skin": skin }) = monster_bullchicken : "BullChicken" [] +@PointClass base(Monster, Sequence) size(-3 -3 0, 3 3 3) model({ "path": "models/roach.mdl", "frame": sequence, "skin": skin }) = monster_cockroach : "Cockroach" [] +@PointClass base(Monster, Sequence) size(-16 -16 0, 16 16 16) model({ "path": "models/aflock.mdl", "frame": sequence, "skin": skin }) = monster_flyer_flock : "Flock of Flyers" +[ + iFlockSize(Integer) : "Flock Size" : 8 + flFlockRadius(Integer) : "Flock Radius" : 128 +] +@PointClass base(Monster, Sequence) size(-16 -16 0, 16 16 72) studio() = monster_furniture : "Monster Furniture" +[ + model(studio) : "model" + +] +@PointClass base(Monster, Sequence) size(-32 -32 0, 32 32 128) model({ "path": "models/garg.mdl", "frame": sequence, "skin": skin }) = monster_gargantua : "Gargantua" [] +@PointClass base(Monster, RenderFields, Sequence) size(-16 -16 -36, 16 16 36) studio() = monster_generic : "Generic Script Monster" +[ + spawnflags(Flags) = + [ + 4 : "Not solid" : 0 + ] + model(studio) : "model" + body(Integer) : "Body" : 0 +] +@PointClass base(Monster, Sequence) size(-16 -16 0, 16 16 72) model({ "path": "models/gman.mdl", "frame": sequence, "skin": skin }) = monster_gman : "G-Man" [] +@PointClass base(Monster, Sequence) size(-16 -16 0, 16 16 72) model({ "path": "models/hgrunt.mdl", "frame": sequence, "skin": skin }) = monster_grunt_repel : "Human Grunt (Repel)" [] +@PointClass base(Weapon, Targetx, RenderFields, Sequence) model({ "path": "models/w_grenade.mdl", "frame": sequence, "skin": skin }) = monster_handgrenade : "Live Handgrenade" [] +@PointClass base(Monster, Sequence) size(-16 -16 0, 16 16 36) model({ "path": "models/headcrab.mdl", "frame": sequence, "skin": skin }) = monster_headcrab : "Head Crab" [] +@PointClass base(Appearflags,RenderFields, Angles, Sequence) size(-16 -16 0, 16 16 72) = monster_hevsuit_dead : "Dead HEV Suit" +[ + pose(Choices) : "Pose" : 0 = + [ + 0 : "On back" + 1 : "Seated" + 2 : "On stomach" + 3 : "On Table" + ] +] +@PointClass base(Appearflags,RenderFields, Angles) size(-16 -16 0, 16 16 72) model({ "path": "models/hgrunt.mdl", "frame": sequence, "skin": skin }) = monster_hgrunt_dead : "Dead Human Grunt" +[ + pose(Choices) : "Pose" : 0 = + [ + 0 : "On stomach" + 1 : "On side" + 2 : "Seated" + ] + body(Choices) : "Body" : 0 = + [ + 0 : "Grunt with Gun" + 1 : "Commander with Gun" + 2 : "Grunt no Gun" + 3 : "Commander no Gun" + ] + sequence(Choices) : "Animation Sequence (editor)" : 44 = + [ + 44 : "deadstomach" + 45 : "deadside" + 46 : "deadsitting" + ] +] +@PointClass base(Monster, Sequence) size(-16 -16 0, 16 16 36) model({ "path": "models/houndeye.mdl", "frame": sequence, "skin": skin }) = monster_houndeye : "Houndeye" +[ + netname(string) : "Squad Name" + spawnflags(Flags) = + [ + 32 : "SquadLeader" : 0 + ] +] +@PointClass base(Monster, Sequence) size(-16 -16 0, 16 16 72) model({ "path": "models/hassassin.mdl", "frame": sequence, "skin": skin }) = monster_human_assassin : "Human Assassin" [] +@PointClass base(Monster) size(-16 -16 0, 16 16 72) model({ "path": "models/hgrunt.mdl", "frame": sequence, "skin": skin }) = monster_human_grunt : "Human Grunt (camo)" +[ + spawnflags(Flags) = + [ + 32 : "SquadLeader" : 0 + ] + netname(string) : "Squad Name" + weapons(Choices) : "Weapons" : 1 = + [ + 1 : "9mmAR" + 3 : "9mmAR + HG" + 5 : "9mmAR + GL" + 8 : "Shotgun" + 10 : "Shotgun + HG" + ] + sequence(Choices) : "Animation Sequence (editor)" : 11 = + [ + 0 : "walk1" + 1 : "run" + 2 : "victorydance" + 3 : "cower" + 4 : "smflinch" + 5 : "leftlegsmflinch" + 6 : "rightlegsmflinch" + 7 : "rightarmflinch" + 8 : "leftarmflinch" + 9 : "launchgrenade" + 10 : "throwgrenade" + 11 : "idle1" + 12 : "idle2" + 13 : "combatidle" + 14 : "frontkick" + 15 : "crouching_idle" + 16 : "crouching_wait" + 17 : "crouching_mp5" + 18 : "standing_mp5" + 19 : "reload_mp5" + 20 : "crouching_shotgun" + 21 : "standing_shotgun" + 22 : "reload_shotgun" + 23 : "advance_signal" + 24 : "flank_signal" + 25 : "retreat_signal" + 26 : "drop_grenade" + 27 : "limpingwalk" + 28 : "limpingrun" + 29 : "180L" + 30 : "180R" + 31 : "strafeleft" + 32 : "straferight" + 33 : "dieback1" + 34 : "dieforward" + 35 : "diesimple" + 36 : "diebackwards" + 37 : "dieheadshot" + 38 : "diegutshot" + 39 : "barnacled1" + 40 : "barnacled2" + 41 : "barnacled3" + 42 : "barnacled4" + 43 : "dead_on_stomach" + 44 : "deadstomach" + 45 : "deadside" + 46 : "deadsitting" + 47 : "repel_jump" + 48 : "repel_repel" + 49 : "repel_shoot" + 50 : "repel_land" + 51 : "repel_die" + 52 : "dragholeidle" + 53 : "draghole" + 54 : "bustwall" + 55 : "hoprail" + 56 : "converse1" + 57 : "converse2" + 58 : "startleleft" + 59 : "startleright" + 60 : "divecover" + 61 : "defuse" + 62 : "corner1" + 63 : "corner2" + 64 : "stonetoss" + 65 : "cliffdie" + 66 : "diveaside_idle" + 67 : "diveaside" + 68 : "kneeldive_idle" + 69 : "kneeldive" + 70 : "WM_button" + 71 : "WM_moatjump" + 72 : "bustwindow" + 73 : "dragleft" + 74 : "dragright" + 75 : "trackwave" + 76 : "trackdive" + 77 : "flyback" + 78 : "impaled" + 79 : "jumptracks" + 80 : "pipetoss" + 81 : "plunger" + ] +] +@PointClass base(Monster, Sequence) size(-32 -32 0, 32 32 64) model({ "path": "models/icky.mdl", "frame": sequence, "skin": skin }) = monster_ichthyosaur : "Ichthyosaur" [] +@PointClass base(Monster, Sequence) size(-6 -6 0, 6 6 6) model({ "path": "models/leech.mdl", "frame": sequence, "skin": skin }) = monster_leech : "Leech" [] +@PointClass base(Monster, Sequence) size(-16 -16 -32, 16 16 32) model({ "path": "models/miniturret.mdl", "frame": sequence, "skin": skin }) = monster_miniturret : "Mini Auto Turret" +[ + orientation(Choices) : "Orientation" : 0 = + [ + 0 : "Floor Mount" + 1 : "Ceiling Mount" + ] + spawnflags(Flags) = + [ + 32 : "Autostart" : 0 + 64 : "Start Inactive" : 0 + ] +] +@PointClass base(Monster, Sequence) size(-192 -192 0, 192 192 384) model({ "path": "models/nihilanth.mdl", "frame": sequence, "skin": skin }) = monster_nihilanth : "Nihilanth" [] +@PointClass base(Monster, Sequence) size(-480 -480 -112, 480 480 24) model({ "path": "models/osprey.mdl", "frame": sequence, "skin": skin }) = monster_osprey : "Osprey" +[ + spawnflags(Flags) = + [ + 64 : "Start Inactive" : 0 + ] +] +@PointClass base(Monster, Sequence) size(-6 -6 0, 6 6 6) model({ "path": "models/bigrat.mdl", "frame": sequence, "skin": skin }) = monster_rat : "Rat (no ai)" [] +@PointClass base(Weapon,Targetx,RenderFields, Sequence) model({ "path": "models/w_satchel.mdl", "frame": sequence, "skin": skin }) = monster_satchelcharge : "Live Satchel Charge" [] +@PointClass base(Monster, TalkMonster) size(-16 -16 0, 16 16 72) model({ "path": "models/scientist.mdl", "frame": sequence, "skin": skin }) = monster_scientist : "Scared Scientist" +[ + body(Choices) : "Body" : -1 = + [ + -1 : "Random" + 0 : "Glasses" + 1 : "Einstein" + 2 : "Luther" + 3 : "Slick" + ] + sequence(Choices) : "Animation Sequence (editor)" : 13 = + [ + 0 : "walk" + 1 : "walk_scared" + 2 : "run" + 3 : "run1" + 4 : "run2" + 5 : "180_Left" + 6 : "180_Right" + 7 : "flinch" + 8 : "flinch1" + 9 : "laflinch" + 10 : "raflinch" + 11 : "llflinch" + 12 : "rlflinch" + 13 : "idle1" + 14 : "idle3" + 15 : "idle4" + 16 : "idle5" + 17 : "idle6" + 18 : "idle7" + 19 : "crouchstand" + 20 : "crouch_idle" + 21 : "crouch_idle2" + 22 : "crouch_idle3" + 23 : "crouch_idle3" + 24 : "panic" + 25 : "fear1" + 26 : "fear2" + 27 : "eye_wipe" + 28 : "pull_needle" + 29 : "return_needle" + 30 : "give_shot" + 31 : "diesimple" + 32 : "dieforward" + 33 : "dieforward1" + 34 : "diebackward" + 35 : "headshot" + 36 : "gutshot" + 37 : "lying_on_back" + 38 : "lying_on_stomach" + 39 : "dead_sitting" + 40 : "dead_table1" + 41 : "dead_table2" + 42 : "dead_table3" + 43 : "barnacled1" + 44 : "barnacled2" + 45 : "barnacled3" + 46 : "barnacled4" + 47 : "console" + 48 : "checktie" + 49 : "dryhands" + 50 : "tieshoe" + 51 : "whiteboard" + 52 : "studycart" + 53 : "lean" + 54 : "pondering" + 55 : "pondering2" + 56 : "pondering3" + 57 : "buysoda" + 58 : "pause" + 59 : "yes" + 60 : "no" + 61 : "push_button" + 62 : "converse1" + 63 : "converse2" + 64 : "retina" + 65 : "talkleft" + 66 : "talkright" + 67 : "deskidle" + 68 : "coffee" + 69 : "franticbutton" + 70 : "startle" + 71 : "sitlookleft" + 72 : "sitlookright" + 73 : "sitscared" + 74 : "sitting2" + 75 : "sitting3" + 76 : "cprscientist" + 77 : "cprscientistrevive" + 78 : "cowering_in_corner" + 79 : "sstruggleidle" + 80 : "sstruggle" + 81 : "headcrabbed" + 82 : "c1a0_catwalkidle" + 83 : "c1a0_catwalk" + 84 : "ceiling_dangle" + 85 : "ventpull1" + 86 : "ventpull2" + 87 : "ventpullidle1" + 88 : "ventpullidle2" + 89 : "sitidle" + 90 : "sitstand" + 91 : "keypad" + 92 : "panic1" + 93 : "lookwindow" + 94 : "wave" + 95 : "pulldoor" + 96 : "beatdoor" + 97 : "fallingloop" + 98 : "crawlwindow" + 99 : "divewindow" + 100 : "locked_door" + 101 : "push_button2" + 102 : "unlock_door" + 103 : "quicklook" + 104 : "handrailidle" + 105 : "handrail" + 106 : "hanging_idle" + 107 : "fall" + 108 : "scientist_get_pulled" + 109 : "hanging_idle2" + 110 : "fall_elevator" + 111 : "scientist_idlewall" + 112 : "ickyjump_sci" + 113 : "haulscientist" + 114 : "c1a4_wounded_idle" + 115 : "c1a4_dying_speech" + 116 : "tentacle_grab" + 117 : "helicack" + 118 : "windive" + 119 : "scicrashidle" + 120 : "scicrash" + 121 : "onguard" + 122 : "seeya" + 123 : "rocketcrawl" + 124 : "portal" + 125 : "gluonshow" + 126 : "crouch" + 127 : "kneel" + ] +] +@PointClass base(Appearflags,RenderFields, Angles) size(-16 -16 0, 16 16 72) model({ "path": "models/scientist.mdl", "frame": sequence, "skin": skin }) = monster_scientist_dead : "Dead Scientist" +[ + body(Choices) : "Body" : -1 = + [ + -1 : "Random" + 0 : "Glasses" + 1 : "Einstein" + 2 : "Luther" + 3 : "Slick" + ] + pose(Choices) : "Pose" : 0 = + [ + 0 : "On back" + 1 : "On Stomach" + 2 : "Sitting" + 3 : "Hanging" + 4 : "Table1" + 5 : "Table2" + 6 : "Table3" + ] + sequence(Choices) : "Animation Sequence (editor)" : 37 = + [ + 37 : "lying_on_back" + 38 : "lying_on_stomach" + 39 : "dead_sitting" + 40 : "dead_table1" + 41 : "dead_table2" + 42 : "dead_table3" + ] +] +@PointClass base(Monster) size(-14 -14 22, 14 14 72) model({ "path": "models/scientist.mdl", "frame": sequence, "skin": skin }) = monster_sitting_scientist : "Sitting Scientist" +[ + body(Choices) : "Body" : -1 = + [ + -1 : "Random" + 0 : "Glasses" + 1 : "Einstein" + 2 : "Luther" + 3 : "Slick" + ] + sequence(Choices) : "Animation Sequence (editor)" : 73 = + [ + 71 : "sitlookleft" + 72 : "sitlookright" + 73 : "sitscared" + 74 : "sitting2" + 75 : "sitting3" + ] +] +@PointClass base(Monster, Sequence) size(-16 -16 0, 16 16 72) model({ "path": "models/sentry.mdl", "frame": sequence, "skin": skin }) = monster_sentry : "Sentry Turret Gun" +[ + spawnflags(Flags) = + [ + 32 : "Autostart" : 0 + 64 : "Start Inactive" : 0 + ] +] +@PointClass base(Monster, Sequence) size(-16 -16 0, 16 16 36) model({ "path": "models/w_squeak.mdl", "frame": sequence, "skin": skin }) = monster_snark : "Armed Snark" [] +@PointClass base(Monster, Sequence) size(-32 -32 0, 32 32 64) model({ "path": "models/tentacle2.mdl", "frame": sequence, "skin": skin }) = monster_tentacle : "Tentacle Arm" +[ + sweeparc(integer) : "Sweep Arc" : 130 + sound(Choices) : "Tap Sound" : -1 = + [ + -1 : "None" + 0 : "Silo" + 1 : "Dirt" + 2 : "Water" + ] +] +@PointClass base(Monster, Sequence) = monster_tripmine : "Active Tripmine" +[ + spawnflags(Flags) = + [ + 1 : "Instant On" : 1 + ] +] +@PointClass base(Monster, Sequence) size(-32 -32 -32, 32 32 32) model({ "path": "models/turret.mdl", "frame": sequence, "skin": skin }) = monster_turret : "Auto Turret" +[ + orientation(Choices) : "Orientation" : 0 = + [ + 0 : "Floor Mount" + 1 : "Ceiling Mount" + ] + spawnflags(Flags) = + [ + 32 : "Autostart" : 0 + 64 : "Start Inactive" : 0 + ] +] +@PointClass base(Monster, Sequence) size(-16 -16 0, 16 16 72) model({ "path": "models/zombie.mdl", "frame": sequence, "skin": skin }) = monster_zombie : "Scientist Zombie" [] +@PointClass base(Targetname, Angles) size(-16 -16 -16, 16 16 16) = monstermaker : "Monster Maker" +[ + target(string) : "Target On Release" + monstertype(string) : "Monster Type" + netname(string) : "Childrens' Name" + spawnflags(Flags) = + [ + 1 : "Start ON" : 0 + // 2 : "PVS On/Off" : 0 // not implemented + 4 : "Cyclic" : 0 + 8 : "MonsterClip" : 0 + ] + + // how many monsters the monstermaker can create (-1 = unlimited) + monstercount(integer) : "Number of Monsters" : -1 + + // if delay is -1, new monster will be made when last monster dies. + // else, delay is how often (seconds) a new monster will be dookied out. + delay(string) : "Frequency" : "5" + + // maximum number of live children allowed at one time. (New ones will not be made until one dies) + // -1 no limit + m_imaxlivechildren(integer) : "Max live children" : 5 +] + +@PointClass base(Targetname) color(255 128 0) = multi_manager : "MultiTarget Manager" +[ + spawnflags(Flags) = + [ + 1 : "multithreaded" : 0 + ] +] + +@PointClass base(Targetname, Target) color(128 255 128) = multisource : "Multisource" +[ + globalstate(string) : "Global State Master" +] + +@PointClass base(Targetname, Angles) size(16 16 16) color(247 181 82) = path_corner : "Moving platform stop" +[ + spawnflags(Flags) = + [ + 1: "Wait for retrigger" : 0 + 2: "Teleport" : 0 + 4: "Fire once" : 0 + ] + target(target_destination) : "Next stop target" + message(target_destination) : "Fire On Pass" + wait(integer) : "Wait here (secs)" : 0 + speed(integer) : "New Train Speed" : 0 + yaw_speed(integer) : "New Train rot. Speed" : 0 +] + +@PointClass base(Targetname, Angles) size(16 16 16) = path_track : "Train Track Path" +[ + spawnflags(Flags) = + [ + 1: "Disabled" : 0 + 2: "Fire once" : 0 + 4: "Branch Reverse" : 0 + 8: "Disable train" : 0 + ] + target(target_destination) : "Next stop target" + message(target_destination) : "Fire On Pass" + altpath(target_destination) : "Branch Path" + netname(target_destination) : "Fire on dead end" + speed(integer) : "New Train Speed" : 0 +] + +// +// player effects +// + +@PointClass base(Targetname) size(-16 -16 -16, 16 16 16) = player_loadsaved : "Load Auto-Saved game" +[ + duration(string) : "Fade Duration (seconds)" : "2" + holdtime(string) : "Hold Fade (seconds)" : "0" + renderamt(integer) : "Fade Alpha" : 255 + rendercolor(color255) : "Fade Color (R G B)" : "0 0 0" + messagetime(string) : "Show Message delay" : "0" + message(string) : "Message To Display" : "" + loadtime(string) : "Reload delay" : "0" +] + +@PointClass base(Targetname) size(-16 -16 -16, 16 16 16) = player_weaponstrip : "Strips player's weapons" [] + +@PointClass base(Targetname, Targetx) size(-16 -16 0, 16 16 72) color(255 0 255) = scripted_sentence : "Scripted Sentence" +[ + spawnflags(Flags) = + [ + 1 : "Fire Once" : 1 + 2 : "Followers Only" : 0 + 4 : "Interrupt Speech" : 1 + 8 : "Concurrent" : 0 + ] + sentence(string) : "Sentence Name" : "" + entity(string) : "Speaker Type" + duration(string) : "Sentence Time" : "3" + radius(integer) : "Search Radius" : 512 + refire(string) : "Delay Before Refire" : "3" + listener(string) : "Listener Type" + volume(string) : "Volume 0-10" : "10" + attenuation(Choices) : "Sound Radius" : 0 = + [ + 0 : "Small Radius" + 1 : "Medium Radius" + 2 : "Large Radius" + 3 : "Play Everywhere" + ] +] + +@PointClass base(Targetname, Targetx, Angles) size(-16 -16 0, 16 16 72) color(255 0 255) = scripted_sequence : "Scripted Sequence" +[ + m_iszEntity(string) : "Target Monster" + m_iszPlay(string) : "Action Animation" : "" + m_iszIdle(string) : "Idle Animation" : "" + m_flRadius(integer) : "Search Radius" : 512 + m_flRepeat(integer) : "Repeat Rate ms" : 0 + m_fMoveTo(choices) : "Move to Position" : 0 = + [ + 0 : "No" + 1 : "Walk" + 2 : "Run" + 4 : "Instantaneous" + 5 : "No - Turn to Face" + ] + spawnflags(Flags) = + [ + 4 : "Repeatable" : 0 + 8 : "Leave Corpse" : 0 + 32: "No Interruptions" : 0 + 64: "Override AI" : 0 + 128: "No Script Movement" : 0 + ] +] + +@PointClass iconsprite("sprites/speaker.spr") base(Targetname) = speaker : "Announcement Speaker" +[ + preset(choices) :"Announcement Presets" : 0 = + [ + 0: "None" + 1: "C1A0 Announcer" + 2: "C1A1 Announcer" + 3: "C1A2 Announcer" + 4: "C1A3 Announcer" + 5: "C1A4 Announcer" + 6: "C2A1 Announcer" + 7: "C2A2 Announcer" + // 8: "C2A3 Announcer" + 9: "C2A4 Announcer" + // 10: "C2A5 Announcer" + 11: "C3A1 Announcer" + 12: "C3A2 Announcer" + ] + message(string) : "Sentence Group Name" + health(integer) : "Volume (10 = loudest)" : 5 + spawnflags(flags) = + [ + 1: "Start Silent" : 0 + ] +] + +@PointClass base(Targetname) = target_cdaudio : "CD Audio Target" +[ + health(choices) : "Track #" : -1 = + [ + -1 : "Stop" + 1 : "Track 1" + 2 : "Track 2" + 3 : "Track 3" + 4 : "Track 4" + 5 : "Track 5" + 6 : "Track 6" + 7 : "Track 7" + 8 : "Track 8" + 9 : "Track 9" + 10 : "Track 10" + 11 : "Track 11" + 12 : "Track 12" + 13 : "Track 13" + 14 : "Track 14" + 15 : "Track 15" + 16 : "Track 16" + 17 : "Track 17" + 18 : "Track 18" + 19 : "Track 19" + 20 : "Track 20" + 21 : "Track 21" + 22 : "Track 22" + 23 : "Track 23" + 24 : "Track 24" + 25 : "Track 25" + 26 : "Track 26" + 27 : "Track 27" + 28 : "Track 28" + 29 : "Track 29" + 30 : "Track 30" + ] + radius(string) : "Player Radius" +] + +// +// Triggers +// + +@PointClass base(Targetx) = trigger_auto : "AutoTrigger" +[ + spawnflags(Flags) = + [ + 1 : "Remove On fire" : 1 + ] + globalstate(string) : "Global State to Read" + triggerstate(choices) : "Trigger State" : 0 = + [ + 0 : "Off" + 1 : "On" + 2 : "Toggle" + ] +] + +@SolidClass base(Targetname) = trigger_autosave : "AutoSave Trigger" +[ + master(string) : "Master" +] + +@PointClass base(Targetx, Targetname) = trigger_camera : "Trigger Camera" +[ + wait(integer) : "Hold time" : 10 + moveto(string) : "Path Corner" + spawnflags(flags) = + [ + 1: "Start At Player" : 1 + 2: "Follow Player" : 1 + 4: "Freeze Player" : 0 + ] + speed(string) : "Initial Speed" : "0" + acceleration(string) : "Acceleration units/sec^2" : "500" + deceleration(string) : "Stop Deceleration units/sec^2" : "500" +] + +@SolidClass base(Targetname) = trigger_cdaudio : "Trigger CD Audio" +[ + health(choices) : "Track #" : -1 = + [ + -1 : "Stop" + 1 : "Track 1" + 2 : "Track 2" + 3 : "Track 3" + 4 : "Track 4" + 5 : "Track 5" + 6 : "Track 6" + 7 : "Track 7" + 8 : "Track 8" + 9 : "Track 9" + 10 : "Track 10" + 11 : "Track 11" + 12 : "Track 12" + 13 : "Track 13" + 14 : "Track 14" + 15 : "Track 15" + 16 : "Track 16" + 17 : "Track 17" + 18 : "Track 18" + 19 : "Track 19" + 20 : "Track 20" + 21 : "Track 21" + 22 : "Track 22" + 23 : "Track 23" + 24 : "Track 24" + 25 : "Track 25" + 26 : "Track 26" + 27 : "Track 27" + 28 : "Track 28" + 29 : "Track 29" + 30 : "Track 30" + ] +] + +@SolidClass = trigger_changelevel : "Trigger: Change level" +[ + targetname(string) : "Name" + map(string) : "New map name" + landmark(string) : "Landmark name" + changetarget(target_destination) : "Change Target" + changedelay(string) : "Delay before change target" : "0" + spawnflags(flags) = + [ + 1: "No Intermission" : 0 + 2: "USE Only" : 0 + ] +] + +@PointClass base(Targetx, Targetname) = trigger_changetarget : "Trigger Change Target" +[ + m_iszNewTarget(string) : "New Target" +] + +@SolidClass base(Trigger, Targetname) = trigger_counter : "Trigger counter" +[ + spawnflags(flags) = + [ + 1 : "No Message" : 0 + ] + master(string) : "Master" + count(integer) : "Count before activation" : 2 +] + +@SolidClass base(Targetname) = trigger_endsection : "EndSection Trigger" +[ + section(string) : "Section" + spawnflags(flags) = + [ + 1: "USE Only" : 0 + ] +] + +@SolidClass base(Trigger) = trigger_gravity : "Trigger Gravity" +[ + gravity(integer) : "Gravity (0-1)" : 1 +] + +@SolidClass base(Targetname,Target) = trigger_hurt : "Trigger player hurt" +[ + spawnflags(flags) = + [ + 1: "Target Once" : 0 + 2: "Start Off" : 0 + 8: "No clients" : 0 + 16:"FireClientOnly" : 0 + 32:"TouchClientOnly" : 0 + ] + master(string) : "Master" + dmg(integer) : "Damage" : 10 + delay(string) : "Delay before trigger" : "0" + damagetype(choices) : "Damage Type" : 0 = + [ + 0 : "GENERIC" + 1 : "CRUSH" + 2 : "BULLET" + 4 : "SLASH" + 8 : "BURN" + 16 : "FREEZE" + 32 : "FALL" + 64 : "BLAST" + 128 : "CLUB" + 256 : "SHOCK" + 512 : "SONIC" + 1024 : "ENERGYBEAM" + 16384: "DROWN" + 32768 : "PARALYSE" + 65536 : "NERVEGAS" + 131072 : "POISON" + 262144 : "RADIATION" + 524288 : "DROWNRECOVER" + 1048576 : "CHEMICAL" + 2097152 : "SLOWBURN" + 4194304 : "SLOWFREEZE" + ] +] + +@SolidClass base(Angles) = trigger_monsterjump : "Trigger monster jump" +[ + master(string) : "Master" + speed(integer) : "Jump Speed" : 40 + height(integer) : "Jump Height" : 128 +] + +@SolidClass base(Trigger) = trigger_multiple : "Trigger: Activate multiple" +[ + wait(integer) : "Delay before reset" : 10 +] + +@SolidClass base(Trigger) = trigger_once : "Trigger: Activate once" [] + +@SolidClass base(Trigger, Angles) = trigger_push : "Trigger player push" +[ + spawnflags(flags) = + [ + 1: "Once Only" : 0 + 2: "Start Off" : 0 + ] + speed(integer) : "Speed of push" : 40 +] + +@PointClass base(Targetname, Targetx) = trigger_relay : "Trigger Relay" +[ + spawnflags(flags) = + [ + 1: "Remove On fire" : 0 + ] + triggerstate(choices) : "Trigger State" : 0 = + [ + 0: "Off" + 1: "On" + 2: "Toggle" + ] +] + +@SolidClass base(Trigger) = trigger_teleport : "Trigger teleport" [] + +@SolidClass base(Targetname) = trigger_transition : "Trigger: Select Transition Area" [] + +// +// weapons +// + +@PointClass base(Weapon, Targetx) model({ "path": "models/w_crowbar.mdl" }) = weapon_crowbar : "Crowbar" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_9mmhandgun.mdl" }) = weapon_9mmhandgun : "9mm Handgun" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_357.mdl" }) = weapon_357 : "357 Handgun" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_9mmar.mdl" }) = weapon_9mmAR : "9mm Assault Rifle" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_shotgun.mdl" }) = weapon_shotgun : "Shotgun" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_rpg.mdl" }) = weapon_rpg : "RPG" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_gauss.mdl" }) = weapon_gauss : "Gauss Gun" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_crossbow.mdl", "frame": sequence }) = weapon_crossbow : "Crossbow" +[ + sequence(choices) : "Placement" : 0 = + [ + 0 : "Normal (flat)" + 1 : "Realistic (tilted)" + ] +] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_egon.mdl" }) = weapon_egon : "Egon Gun" [] +@PointClass base(Weapon, Targetx) size(-16 -16 -5, 16 16 27) = weapon_tripmine : "Tripmine Ammo" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_satchel.mdl" }) = weapon_satchel : "Satchel Charge Ammo" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_grenade.mdl" }) = weapon_handgrenade : "Handgrenade Ammo" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_squeak.mdl" }) = weapon_snark : "Squeak Grenade" [] +@PointClass base(Weapon, Targetx) model({ "path": "models/w_hgun.mdl" }) = weapon_hornetgun : "Hornet Gun" [] +@PointClass size(-16 -16 0, 16 16 64) color(0 128 0) model({ "path": "models/w_chainammo.mdl" }) = weaponbox : "Weapon/Ammo Container" [] + +@PointClass base(Weapon, Targetx) = world_items : "World Items" +[ + type(choices) :"types" : 42 = + [ + 42: "Antidote" + 43: "Security Card" + 44: "Battery" + 45: "Suit" + ] +] + +// +// Xen +// + +@PointClass base(Target, Targetname, RenderFields, Angles) size(-48 -48 0, 48 48 32 ) model({ "path": "models/light.mdl" }) = xen_plantlight : "Xen Plant Light" [] +@PointClass base(Targetname, RenderFields, Angles) size(-8 -8 0, 8 8 32 ) model({ "path": "models/hair.mdl" }) = xen_hair : "Xen Hair" +[ + spawnflags(Flags) = + [ + 1 : "Sync Movement" : 0 + ] +] +@PointClass base(Targetname, RenderFields, Angles) size(-24 -24 0, 24 24 188 ) model({ "path": "models/tree.mdl" }) = xen_tree : "Xen Tree" [] +@PointClass base(Targetname, RenderFields, Angles) size(-16 -16 0, 16 16 64 ) model({ "path": "models/fungus(small).mdl" }) = xen_spore_small : "Xen Spore (small)" [] +@PointClass base(Targetname, RenderFields, Angles) size(-40 -40 0, 40 40 120 ) model({ "path": "models/fungus.mdl" }) = xen_spore_medium : "Xen Spore (medium)" [] +@PointClass base(Targetname, RenderFields, Angles) size(-90 -90 0, 90 90 220 ) model({ "path": "models/fungus(large).mdl" }) = xen_spore_large : "Xen Spore (large)" [] diff --git a/tools/trenchbroom/games/Halflife/Icon.png b/tools/trenchbroom/games/Halflife/Icon.png new file mode 100644 index 0000000..a41f2ed Binary files /dev/null and b/tools/trenchbroom/games/Halflife/Icon.png differ diff --git a/tools/trenchbroom/games/Heretic2/GameConfig.cfg b/tools/trenchbroom/games/Heretic2/GameConfig.cfg new file mode 100644 index 0000000..a65f97f --- /dev/null +++ b/tools/trenchbroom/games/Heretic2/GameConfig.cfg @@ -0,0 +1,252 @@ +{ + "version": 9, + "name": "Heretic 2", + "icon": "Icon.png", + "fileformats": [ + { "format": "Quake2" }, + { "format": "Quake2 (Valve)"} + ], + "filesystem": { + "searchpath": "base", + "packageformat": { "extension": ".pak", "format": "idpak" } + }, + "materials": { + "root": "textures", + "extensions": [".m8"], + "palette": "pics/colormap.pcx" + }, + "entities": { + "definitions": [ "heretic2.fgd" ], + "defaultcolor": "0.6 0.6 0.6 1.0" + }, + "tags": { + "brush": [ + { + "name": "Trigger", + "attribs": [ "transparent" ], + "match": "classname", + "pattern": "trigger*", + "material": "trigger" + } + ], + "brushface": [ + { + "name": "Clip", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "clip" + }, + { + "name": "Skip", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "skip" + }, + { + "name": "Hint", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "hint*" + }, + { + "name": "Detail", + "match": "contentflag", + "flags": [ "detail" ] + }, + { + "name": "Liquid", + "match": "contentflag", + "flags": [ "lava", "slime", "water" ] + }, + { + "name": "Transparent", + "attribs": [ "transparent" ], + "match": "surfaceflag", + "flags": [ "trans33", "trans66" ] + } + ] + }, + "faceattribs": { + "surfaceflags": [ + { + "name": "light", + "description": "Emit light from the surface, brightness is specified in the 'value' field" + }, // 1 << 0 + { + "name": "slick", + "description": "The surface is slippery" + }, // 1 << 1 + { + "name": "sky", + "description": "The surface is sky, the texture will not be drawn, but the background sky box is used instead" + }, // 1 << 2 + { + "name": "warp", + "description": "The surface warps (like water textures do)" + }, // 1 << 3 + { + "name": "trans33", + "description": "The surface is 33% transparent" + }, // 1 << 4 + { + "name": "trans66", + "description": "The surface is 66% transparent" + }, // 1 << 5 + { + "name": "flowing", + "description": "The texture wraps in a downward 'flowing' pattern (warp must also be set)" + }, // 1 << 6 + { + "name": "nodraw", + "description": "Used for non-fixed-size brush triggers and clip brushes" + }, // 1 << 7 + { + "name": "hint", + "description": "Make a primary bsp splitter" + }, // 1 << 8 + { + "name": "skip", + "description": "Completely ignore, allowing non-closed brushes" + }, // 1 << 9 + { + "name": "tall_wall", + "description": "Purpose unknown" + }, // 1 << 10 + { + "name": "alpha_tex", + "description": "Purpose unknown" + }, // 1 << 11 + { + "name": "animspeed", + "description": "Purpose unknown" + }, // 1 << 12 + { + "name": "undulate", + "description": "Purpose unknown" + }, // 1 << 13 + { + "name": "skyreflect", + "description": "Purpose unknown" + }, // 1 << 14 + { "unused": true }, // 1 << 15 + { "unused": true }, // 1 << 16 + { "unused": true }, // 1 << 17 + { "unused": true }, // 1 << 18 + { "unused": true }, // 1 << 19 + { "unused": true }, // 1 << 20 + { "unused": true }, // 1 << 21 + { "unused": true }, // 1 << 22 + { "unused": true }, // 1 << 23 + { + "name": "metal", + "description": "Sound when walked on" + }, // 1 << 24 + { + "name": "stone", + "description": "Sound when walked on" + } // 1 << 25 + ], + "contentflags": [ + { + "name": "solid", + "description": "Default for all brushes" + }, // 1 << 0 + { + "name": "window", + "description": "Brush is a window (not really used)" + }, // 1 << 1 + { + "name": "pushpull", + "description": "Purpose unknown" + }, // 1 << 2 + { + "name": "lava", + "description": "The brush is lava" + }, // 1 << 3 + { + "name": "slime", + "description": "The brush is slime" + }, // 1 << 4 + { + "name": "water", + "description": "The brush is water" + }, // 1 << 5 + { + "name": "mist", + "description": "The brush is non-solid" + }, // 1 << 6 + { "unused": true }, // 1 << 7 + { "unused": true }, // 1 << 8 + { "unused": true }, // 1 << 9 + { "unused": true }, // 1 << 10 + { "unused": true }, // 1 << 11 + { "unused": true }, // 1 << 12 + { "unused": true }, // 1 << 13 + { "unused": true }, // 1 << 14 + { + "name": "areaportal", + "description": "Purpose unknown" + }, // 1 << 15 + { + "name": "playerclip", + "description": "Player cannot pass through the brush (other things can)" + }, // 1 << 16 + { + "name": "monsterclip", + "description": "Monster cannot pass through the brush (player and other things can)" + }, // 1 << 17 + { + "name": "current_0", + "description": "Brush has a current in direction of 0 degrees" + }, // 1 << 18 + { + "name": "current_90", + "description": "Brush has a current in direction of 90 degrees" + }, // 1 << 19 + { + "name": "current_180", + "description": "Brush has a current in direction of 180 degrees" + }, // 1 << 20 + { + "name": "current_270", + "description": "Brush has a current in direction of 270 degrees" + }, // 1 << 21 + { + "name": "current_up", + "description": "Brush has a current in the up direction" + }, // 1 << 22 + { + "name": "current_dn", + "description": "Brush has a current in the down direction" + }, // 1 << 23 + { + "name": "origin", + "description": "Special brush used for specifying origin of rotation for rotating brushes" + }, // 1 << 24 + { + "name": "monster", + "description": "Purpose unknown" + }, // 1 << 25 + { + "name": "deadmonster", + "description": "Purpose unknown" + }, // 1 << 26 + { + "name": "detail", + "description": "Detail brush" + }, // 1 << 27 + { + "name": "translucent", + "description": "Use for opaque water that does not block vis" + }, // 1 << 28 + { + "name": "ladder", + "description": "Brushes with this flag allow a player to move up and down a vertical surface" + }, // 1 << 29 + { + "name": "camnoblock", + "description": "Doesn't block camera" + } // 1 << 30 + ] + } +} diff --git a/tools/trenchbroom/games/Heretic2/Icon.png b/tools/trenchbroom/games/Heretic2/Icon.png new file mode 100644 index 0000000..28e906e Binary files /dev/null and b/tools/trenchbroom/games/Heretic2/Icon.png differ diff --git a/tools/trenchbroom/games/Heretic2/heretic2.fgd b/tools/trenchbroom/games/Heretic2/heretic2.fgd new file mode 100644 index 0000000..7c503de --- /dev/null +++ b/tools/trenchbroom/games/Heretic2/heretic2.fgd @@ -0,0 +1,1873 @@ +// Heretic 2 demo forge game definition file (.fgd) +// for Worldcraft 1.6 and above +// last update: 8 nov 98 +// Ver 0.00000000008 + +// Written by Manly Jack / jarad@ihug.co.nz +// email me with improvements and suggestions. +// Based on the default quake2 fdg so most comments are from that. Things I have added are with a +// h2 comment. +// Damn this is a mess. I wrote most of this up within a week or 2 of the demo being released. +// +// special thanks to: Tiglari for the .ent files +// + +// Revised by whirledtsar on July 27 2020, based on source code + +//---------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------- + +// +// worldspawn +// + +@SolidClass = worldspawn : "World entity" +[ + message(string) : "Level name" + nextmap(string) : "Next map (DM only)" + sky(string) : "Environment map name" + skyaxis(string) : "Vector axis for rotating sky" + skyrotate(integer) : "Speed of rotation (degrees/second)" + sounds(integer) : "CD Track Number" : 1 + gravity(integer) : "Gravity" : 800 + offensive(choices) : "Starting offensive weapons (not for single-player)" = + [ + 1 : "Staff" + 2 : "Fireball" + 4 : "Hellstaff" + 8 : "Magic Missile" + 16 : "Storm Bow" + 32 : "Sphere Of Annihilation" + 64 : "Phoenix Bow" + 128 : "Mace Balls" + 256 : "Firewall" + ] + defensive(choices) : "Starting defensive weapons (not for single-player)" = + [ + 1 : "Ring of Repulsion" + 2 : "Lightning Shield" + 4 : "Teleport" + 8 : "Morph Ovum" + 16 : "Meteor Barrier" + ] + light(integer) : "Light" + + cooptimeout(integer) : "Seconds to wait for all clients to have joined a map in coop" + skinnum(integer) : "Plague level for Corvus (0-2)" +] + +// +// base marker definitions - Appearflags=Spawnflags +// + +@baseclass = Appearflags [ + spawnflags(Flags) = + [ + 256 : "Not in Easy" : 0 + 512 : "Not in Normal" : 0 + 1024 : "Not in Hard" : 0 + 2048 : "Not in Deathmatch" : 0 + ] +] + +@baseclass = Targetname [ targetname(target_source) : "Name" ] +@baseclass = Target [ target(target_destination) : "Target" ] + +// +// player start, deathmatch, coop, deathmatch intermission +// + +@baseclass base(Appearflags, Targetname) size(-16 -16 -24, 16 16 32) color(0 255 0) = PlayerClass [] + + +@PointClass base(PlayerClass) = info_player_start : "Player 1 start" [] +@PointClass base(PlayerClass) = info_player_deathmatch : "Player deathmatch start" [] +@PointClass base(PlayerClass) = info_player_coop : "Player cooperative start" [] +@PointClass base(PlayerClass) = info_player_intermission : "Deathmatch intermission point" +[ + angles(string) : "pitch yaw roll" +] + +// H2 - Check +@PointClass base(PlayerClass, Target, Targetname) = info_buoy : "Buoy for monster navigation + +THE BUOY TEN COMMANDMENTS as Handed Down to M0535 on Mount Sine-AI: + 0) Thou shalt not give a buoy more than one targetname + 1) Thou shalt have a buoy target up to two OTHER buoies + 2) Thou shalt connect each buoy to up to three other buoies (only three lines can come off a buoy) + 3) Thou shalt knowest that direction of connection does not matter unless you are trying to make a one-way buoy (see ONEWAY) + 4) Thou shalt place thine buoy in an area that a monster can fit into + 5) Thou shalt place thine buoies such that each buoy can 'see' each buoy it's conencted to (have a clear line of sight) + 6) Thou shalt knowest that buoies do not need to be placed throughout wide open areas, monsters can get around fine there. + 7) Thou shalt not place buoies in the ground or walls or any other world object + 8) Thou shalt not give any two buoies the same targetname, and each buoy should have a targetname, even if it is not targeted (this is for debug purposes) + 9) Thou shalt not have any other AI system above the BUOYAH! Navigation System. + +Keep in mind that when choosing a buoy, monsters need to be able to find a buoy withing 1024 map units of them. So make sure buoies are placed so that wherever they can get, they are within 1024 of a buoy. +" +[ + spawnflags(flags) = + [ + 1 : "Jump" + 2 : "Activate" : 0 : "Will allow monster to activate doors, triggers, plats, etc. NOTE: the activated object's 'pathtargetname' must match the buoy's 'pathtarget' field." + 4 : "" + 8 : "One-way" : 0 : "This buoy will not allow buoys it's targeting to send monsters backwards along the path. Basically, does not back-link, paths from it to buoys it's targeting become one-way." + ] + delay(integer) : "Time monster waits after using pathtarget" + height(integer) : "Height of jump" : 400 + jumptarget(target_destination) : "JumpTarget" : "used with JUMP - this buoy will only make monsters jump at the buoy whose 'targetname' is the same as 'jumpbuoy'- without this, the buoy WILL NOT MAKE MONSTERS JUMP!" + pathtarget(target_destination) : "Target to use when monster reaches buoy. Requires 'Activate' spawnflag" + speed(integer) : "Speed of jump" : 400 + target(target_destination) : "Next buoy" + target2(target_destination) : "Next buoy (alternate)" + wait(integer) : "Time before monster can use pathtarget again" +] + + +// Notes on the 'team' key: First of all, it's really only useful in DM because it creates a +// random respawn pattern. Let's say that in one spot, you want to have the shotgun, Quad +// damage and mega health item to respawn in alternance. Place all of them in approximately +// the same location, team them and voila! The FIRST item that you place in the map will be +// the team MASTER - the others will be SLAVES. In DM play, the Master will be the first one +// to spawn. Once the Master is picked up, the respawn pattern becomes RANDOM: it could be +// the same or one of the other 2. If you try to use this in a Single Player map, it's +// pretty useless because only the team MASTER spawns and the others never appear obviously. + + +// Keep in mind when using func_areaportal that it must +// *completely* separate two areas. otherwise, you will +// get an error message and the areaportal will not work +// + +@SolidClass base(Appearflags, Targetname) = func_areaportal : "Area portal (Vis blocker)" [] + +@SolidClass base(Appearflags, Target, Targetname) color(0 128 204) = func_button : "Button" +[ + angle(integer) : "Angle" + killtarget(string) : "Kill Target" + pathtarget(string) : "Elevator level target" + speed(integer) : "Speed" : 40 + wait(choices) : "Wait before reset" : 1 = + [ + -1 : "Never Return" + ] + lip(integer) : "Lip remaining after move" : 4 + health(integer) : "Health (shootable)" + sounds(choices) : "Sounds" : 0 = + [ + 0 : "Silent" + 1 : "Generic button" + 2 : "Clanky button" + 3 : "Steam button" + ] + message(string) : "Activation message" + _minlight(integer) : "Minimum light (0-1)" +] + +// H2 +@SolidClass base(Appearflags, Targetname) color(0 128 204) = func_monsterspawner : "Monster Spawner" +[ + spawnflags(flags) = + [ + 1 : "On death" + 2 : "Spawn at random buoy" + 4 : "Not angry" + ] + style(choices) : "Type of monster" : 3 = + [ + 0 : "Nothing" + 1 : "Rat" + 2 : "Plague Elf" + 3 : "Plague Spreader" + 4 : "Gorgon" + 5 : "Chkroktk" + 6 : "Tchekrik (male)" + 7 : "Tchekrik (female)" + 8 : "Tchekrik Mothers" + 9 : "High Priestess" + 10 : "Ogle" + 11 : "Seraph Overlord" + 12 : "Seraph Guard" + 13 : "Assassin" + 14 : "Morcalavin" + 15 : "Dranor" + 16 : "Sidhe Guard" + 17 : "Siernan" + 18 : "Ssithra Scout" + 19 : "Ssithra Victim" + 20 : "Ssithra Mutant" + 21 : "Harpy" + 22 : "Fish" + 23 : "Chicken" + 24 : "Plague Ssithra" + 25 : "Gkrokon" + 26 : "Giant Rat" + 27 : "Palace Plague Guard" + 28 : "Palace Plague Guard (invisible)" + ] + count(integer) : "Count" + distance(integer) : "Radius from spawner" + jump_chance(integer) : "Jump chance of monster" + melee_range(integer) : "Melee range of monster" + missile_range(integer) : "Missile range of monster" + mintel(integer) : "Mintel of monster" + wait(integer) : "Time between spawns" +] + +@BaseClass base(Appearflags, Targetname, Target) = Door +[ + sounds(choices) : "Sound type" : 0 = + [ + 0 : "Silent" + 1 : "Generic" + 2 : "Heavy stone" + 3 : "Palace swing arm" + 4 : "Palace stone bridge" + 5 : "Small wood door" + 6 : "Large wood door" + 7 : "Small stone/wood door" + 8 : "Large stone/wood door" + 9 : "Average metal swinging" + 10 : "Fast sliding" + 11 : "Hive, metal, multipaneled sliding" + 12 : "Huge stone swinging" + 13 : "Large elevator" + 14 : "Crane (warehouse)" + 15 : "Mine pump" + 16 : "Sliding metal (Cloud Labs)" + 17 : "Rotating table (Clodu Labs)" + 18 : "Piston" + 19 : "Short metal clang" + 20 : "Going underwater" + 21 : "Bam" + ] + angle(integer) : "Direction" + dmg(integer) : "Damage when blocked" : 2 + health(integer) : "Health (shootable)" + wait(choices) : "Wait before close" : 5 = + [ + -1 : "Stay open" + ] +] + +@SolidClass base(Door) color(0 128 204) = func_door : "Door" +[ + spawnflags(Flags) = + [ + 1 : "Start Open" : 0 + 4 : "Crusher" : 0 : "Crush blocking entities rather than returning" + 8 : "No Monsters" : 0 + 16 : "Animated" : 0 + 32 : "Toggle" : 0 + 64 : "Animated Fast" : 0 + ] + angle(integer) : "Angle" : 0 + height(integer) : "Absolute move distance (optional)" + killtarget(string) : "Kill Target" + team(integer) : "Linked door group" : 0 : "Doors with matching team numbers will open together" + message(string) : "Message for targetted door" + speed(integer) : "Speed" : 100 + lip(integer) : "Lip remaining after move" : 8 + _minlight(integer) : "Minimum light (0-1)" +] + +@SolidClass base(Door) color(0 128 204) = func_door_rotating : "Rotating Door" +[ + spawnflags(Flags) = + [ + 1 : "Start Open" : 0 + 2 : "Reverse" : 0 + 4 : "Crusher" : 0 + 8 : "No Monsters" : 0 + 16 : "Animated" : 0 + 32 : "Toggle" : 0 + 64 : "X Axis" : 0 + 128 : "Y Axis" : 0 + 256 : "Swing away" : 0 + ] + killtarget(string) : "Kill Target" + team(string) : "Team" + distance(integer) : "Degrees of rotation" : 90 + message(string) : "Message for targetted door" + speed(integer) : "Speed" : 100 + wait(choices) : "Wait before close" : 3 = + [ + -1 : "Stay open" + -2 : "Never stop" + ] + _minlight(integer) : "Minimum light (0-1)" +] + + +@SolidClass base(Door) color(0 128 204) = func_door_secret : "Secret Door" +[ + spawnflags(Flags) = + [ + 1 : "Always shoot" : 0 + 2 : "1st Left" : 0 + 4 : "1st Down" : 0 + ] + message(string) : "Message" + _minlight(integer) : "Minimum light (0-1)" +] + +// h2 +@SolidClass base(Appearflags, Targetname, Target) color(0 128 204) = breakable_brush : "Exploding/Breakable brush" +[ + spawnflags(Flags) = + [ + 1 : "Kill all touching breakables" : 0 + 2 : "Don't link to other breakables" : 0 + 4 : "" : 0 + 8 : "Translucent" : 0 + 16 : "Invulnerable" : 0 + 32 : "Invisible" : 0 + 64 : "Pull/pushable" : 0 + 128 : "Player can't damage" : 0 + ] + materialtype(choices) : "Material Type" : 1 = + [ + 1 : "Grey stone" + 2 : "Cloth" + 3 : "Metal" + 4 : "Flesh" + 5 : "Pottery" + 6 : "Glass" + 7 : "Leaf" + 8 : "Wood" + 9 : "Brown stone" + 10 : "None (still makes smoke)" + ] + model(string): "Model" + health(integer) : "Health" : 100 + mass(integer) : "Mass (debris)" : 75 + dmg(integer) : "Damage" : 0 + + _minlight(integer) : "Minimum light (0-1)" +] + +@SolidClass base(Appearflags, Targetname) color (0 128 204) = func_object : "Solid bmodel, will fall if its support is removed" +[ + spawnflags(Flags) = + [ + 1 : "Trigger Spawn" : 0 + 2 : "Animated" : 0 + 4 : "Animated Fast" : 0 + ] + dmg(integer) : "Damage" : 100 + _minlight(integer) : "Minimum light (0-1)" +] + +@SolidClass base(Appearflags, Targetname) color(0 128 204) = func_plat : "Platform" +[ + spawnflags(Flags) = + [ + 1 : "Plat Low Trigger" : 0 + 4 : "Crush" : 0 : "Crush blocking entities rather than returning" + ] + speed(integer) : "Speed" : 200 + accel(integer) : "Acceleration" : 500 + lip(integer) : "Lip remaining after move" : 8 + height(integer) : "Movement distance" + sounds(choices) : "Sound type" : 0 = + [ + 0 : "Silent" + 1 : "Generic" + 2 : "Heavy stone" + 3 : "Palace swing arm" + 4 : "Palace stone bridge" + 5 : "Small wood door" + 6 : "Large wood door" + 7 : "Small stone/wood door" + 8 : "Large stone/wood door" + 9 : "Average metal swinging" + 10 : "Fast sliding" + 11 : "Hive, metal, multipaneled sliding" + 12 : "Huge stone swinging" + 13 : "Large elevator" + 14 : "Crane (warehouse)" + 15 : "Mine pump" + 16 : "Sliding metal (Cloud Labs)" + 17 : "Rotating table (Clodu Labs)" + 18 : "Piston" + 19 : "Short metal clang" + 20 : "Going underwater" + 21 : "Bam" + ] + _minlight(integer) : "Minimum light (0-1)" +] + + +@SolidClass base(Appearflags, Targetname) color(0 128 204) = func_rotating : "Rotating brush" +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + 2 : "Reverse" : 0 + 4 : "X Axis" : 0 + 8 : "Y Axis" : 0 + 16 : "Pain on Touch" : 0 + 32 : "Block Stops" : 0 + 64 : "Animated" : 0 + 128 : "Animated Fast" : 0 + ] + sounds(choices) : "Sound type" : 0 = + [ + 0 : "Silent" + 1 : "Generic" + 2 : "Huge wheel (Mines)" + 3 : "Rock crusher (Mines)" + 4 : "Spanking paddles (Gauntlet)" + ] + team(string) : "Team" + speed(integer) : "Speed" : 100 + dmg(integer) : "Damage when blocked" : 2 + _minlight(integer) : "Minimum light (0-1)" +] + +@PointClass base(Appearflags, Targetname, Target) color(76 25 153) size(-8 -8 -8, 8 8 8) = func_timer : "Timer" +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + ] + wait(integer) : "Base wait time" : 1 + random(integer) : "Wait variance (+/-)" + delay(integer) : "Delay before first firing" + pausetime(integer) : "Additional delay when used the first time if spawned with 'start on'" +] + + +@SolidClass base(Appearflags, Targetname) color(0 128 204) = func_train : "Moving platform" +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + 2 : "Toggle" : 0 + 4 : "Block Stops" : 0 + 8 : "Use origin brush" : 0 + 16 : "Not solid" + ] + materialtype(choices) : "Material type" : 1 = + [ + 0 : "MAT_WOOD" + 1 : "MAT_GREYSTONE" + 2 : "MAT_CLOTH" + 3 : "MAT_METAL" + 9 : "MAT_BROWNSTONE" + 10 : "MAT_NONE" + ] + wait(choices) : "Wait" : 0 = + [ + -1 : "stop and don't move again until triggered" + -3 : "stop and explode" + -4 : "go through animations (only if a model)" + ] + target(string) : "First stop target" + team(string) : "Team" + speed(integer) : "Speed" : 100 + dmg(integer) : "Damage when blocked" : 2 + count(integer) : "Number of animation frames (for models)" + file(string) : "Model (path/file.fm)" + noise(string) : "Sound (path/file.wav)" + rotate(integer) : "Speed of rotation" + _minlight(integer) : "Minimum light (0-1)" +] + + +@SolidClass base(Appearflags, Targetname) color(0 128 204) = func_wall : "Solid Wall" +[ + spawnflags(Flags) = + [ + 1 : "Trigger Spawn" : 0 + 2 : "Toggle" : 0 + 4 : "Start On" : 0 + 8 : "Animated" : 0 + 16 : "Animated Fast" : 0 + ] + _minlight(integer) : "Minimum light (0-1)" +] + +@SolidClass base(Appearflags, Targetname) color(0 128 204) = func_water : "Moveable water" +[ + angle(choices) : "Direction" = + [ + -1 : "Up" + -2 : "Down" + ] + spawnflags(Flags) = + [ + 1 : "Start Open" : 0 + ] + speed(integer) : "Speed" : 25 + wait(choices) : "Wait before return" : -1 = + [ + -1 : "Toggle" + ] + lip(integer) : "Lip remaining after move" + sounds(Choices) : "Sounds" : 1 = + [ + 0 : "No Sounds" + 1 : "Water" + 2 : "Lava" + ] + team(string) : "Team" + _minlight(integer) : "Minimum light (0-1)" +] + +@PointClass base(Appearflags, Targetname) color(0 128 0) size(-4 -4 -4, 4 4 4) = info_null : "Spotlight target" [] +@PointClass base(info_null) = info_notnull : "Lightning target" [] + +// +// Weapons/Items +// + +@BaseClass base(Appearflags, Target, Targetname) color(76 76 255) size(-16 -16 -16, 16 16 16) = Items +[ + spawnflags(Flags) = + [ + 1 : "Coop only" + 2 : "Don't drop" + ] + team(string) : "Team" +] + +@PointClass base(Items) = item_weapon_firewall : "Firewall" [] +@PointClass base(Items) = item_weapon_maceballs : "Maceballs" [] +@PointClass base(Items) = item_weapon_phoenixbow : "Phoenix Bow" [] +@PointClass base(Items) = item_weapon_sphereofannihilation : "Sphere of Annihilation" [] +@PointClass base(Items) = item_weapon_redrain_bow : "Red Rain Bow" [] +@PointClass base(Items) = item_weapon_magicmissile : "Magic Missile" [] +@PointClass base(Items) = item_weapon_hellstaff : "Hell Staff" [] + +@PointClass base(Items) = item_ammo_hellstaff : "Hellstaff ammo" [] +@PointClass base(Items) = item_ammo_phoenix : "Phoenix ammo" [] +@PointClass base(Items) = item_ammo_redrain : "Red rain ammo" [] + +@PointClass base(Items) = item_health_full : "Full Health" [] +@PointClass base(Items) = item_health_half : "Half Health" [] + +@PointClass base(Items) = item_mana_combo_half : "Half Combo Mana" [] +@PointClass base(Items) = item_mana_combo_quarter : "Quater Combo Mana" [] + +@PointClass base(Items) = item_mana_defensive_full : "Full Defensive Mana" [] +@PointClass base(Items) = item_mana_defensive_half : "Half Defensive Mana" [] +@PointClass base(Items) = item_mana_offensive_full : "Full Offensive Mana" [] +@PointClass base(Items) = item_mana_offensive_half : "Half Offensive Mana" [] + +@PointClass base(Items) = item_defense_meteorbarrier : "Meteor Barrier spell" [] +@PointClass base(Items) = item_defense_shield : "Shield Spell" [] +@PointClass base(Items) = item_defense_polymorph : "Polymorph Spell" [] +@PointClass base(Items) = item_defense_teleport : "Teleport Spell" [] +@PointClass base(Items) = item_defense_ringofrepulsion : "Ring of Repulsion" [] +@PointClass base(Items) = item_defense_powerup : "Tome Powerup - non-functional in single-player" [] +@PointClass base(Items) = item_defense_tornado : "Whirlwind spell (Enhancement patch)" [] + +@PointClass base(Items) = item_puzzle_canyonkey : "Canyon key" [] +@PointClass base(Items) = item_puzzle_cog : "Cog" [] +@PointClass base(Items) = item_puzzle_cloudkey : "Cloud Fortress key" [] +@PointClass base(Items) = item_puzzle_crystal : "Andoria crystal" [] +@PointClass base(Items) = item_puzzle_dungeonkey : "Dungeon key" [] +@PointClass base(Items) = item_puzzle_highpriestesskey : "High Priestess key" [] +@PointClass base(Items) = item_puzzle_highpriestesssymbol : "High Priestess symbol" [] +@PointClass base(Items) = item_puzzle_hive2amulet : "Hive amulet" [] +@PointClass base(Items) = item_puzzle_hive2gem : "Hive gem" [] +@PointClass base(Items) = item_puzzle_hive2spear : "Hive spear" [] +@PointClass base(Items) = item_puzzle_minecartwheel : "Minecart wheel" [] +@PointClass base(Items) = item_puzzle_ore : "Unrefined ore" [] +@PointClass base(Items) = item_puzzle_refinedore : "Refined ore" [] +@PointClass base(Items) = item_puzzle_shield : "Ssithra shield" [] +@PointClass base(Items) = item_puzzle_potion : "Healer potion" [] +@PointClass base(Items) = item_puzzle_slumcontainer : "Andoria container" [] +@PointClass base(Items) = item_puzzle_plazacontainer : "Andoria container" [] +@PointClass base(Items) = item_puzzle_tavernkey : "Tavern key" [] +@PointClass base(Items) = item_puzzle_tome : "Tome" [] +@PointClass base(Items) = item_puzzle_townkey : "Town key" [] + +@PointClass base(Items) = item_spitter : "Triggered item spawner" +[ + spawnflags(flags) = + [ + 1 : "No flash" + ] + angles(integer) : "Angles" + count(integer) : "Count" + radius(integer) : "Radius" + target(string) : "Classname of items to create" + spawnflags2(integer) : "Spawnflags for items created" +] + +// +// Lights +// + +@PointClass base(Appearflags, Target, Targetname) color(0 255 0) size(-8 -8 -8, 8 8 8) = light : "Light" +[ + spawnflags(Flags) = + [ + 8 : "Start Off" : 0 + ] + light(integer) : "Brightness" : 300 + _color(color1) : "RGB Color" + style(Choices) : "Style" : 0 = + [ + 0 : "Normal" + 1 : "Flicker #1" + 6 : "Flicker #2" + 2 : "Slow Strong Pulse" + 3 : "Candle #1" + 7 : "Candle #2" + 8 : "Candle #3" + 4 : "Fast Strobe" + 5 : "Gentle Pulse #1" + 9 : "Slow Strobe" + 10 : "Fluorescent Flicker" + 11 : "Slow pulse, no black" + ] + _cone(integer) : "Size of light (spotlight)" : 10 +] + +@PointClass base(light) size(-7 -7 -7, 7 7 25) = light_buglight : "Bug light" +[ + spawnflags(flags) = + [ + 16 : "No halo" + ] +] +@PointClass base(light) size(-36 -36 -43, 34 34 43) = light_chandelier1 : "Chandelier (dirty gold) A tarnished gold chandelier hung from chains." [] +@PointClass base(light) size(-18 -18 -40, 18 18 40) = light_chandelier2 : "Chandelier (dirty metal) A tarnished metal chandelier hung from chains." [] +@PointClass base(light) size(-34 -34 -80, 34 34 0) = light_chandelier3 : "Chandelier (gold & large) A golden chandelier." [] +@PointClass base(light) size(-14 -14 -17, 14 14 17) = light_floortorch : "Floor torch stand" [] +@PointClass base(light) size(-1 -6 -8, 4 6 8) = light_gem2 : "Gem light" +[ + spawnflags(flags) = + [ + 16 : "No halo" + ] + style(choices) = + [ + 0 : "Yellow" + 1 : "Green" + ] +] +@PointClass base(light) size(-28 -8 -22, 4 8 22) = light_lantern1 : "Lantern with wood arm" +[ + spawnflags(flags) = + [ + 16 : "No halo" + ] +] +@PointClass base(light_lantern1) size(-6 -6 -24, 6 6 40) = light_lantern2 : "Lantern on chain" [] +@PointClass base(light_lantern1) size(-6 -6 -12, 6 6 11) = light_lantern3 : "Lantern (ceiling)" [] +@PointClass base(light_lantern1) size(-18 -7 -7, 7 7 14) = light_lantern4 : "Lantern (wall)" [] +@PointClass base(light_lantern1) size(-7 -7 -7, 7 7 14) = light_lantern5 : "Lantern (table)" [] +@PointClass base(light) size(-4 -6 -5, 6 6 20) = light_torch1 : "Wall torch with blue gem" +[ + spawnflags(flags) = + [ + 16 : "No halo" + ] +] +@PointClass base(light) size(-16 -10 -12, 10 10 12) = light_walltorch : "Wall Torch" +[ + spawnflags(flags) = + [ + 2 : "Flame" + ] +] + +// actor code is still broken...leaving this in because i know *someone* will fix +// this because its pretty damn cool. +@PointClass base(PlayerClass, Target) = misc_actor : "Actor" +[ + health(integer) : "Health" : 100 +] +@PointClass base(Appearflags, Targetname) = target_actor : "Actor path" +[ + spawnflags(Flags) = + [ + 1 : "Jump" : 0 + 2 : "Shoot" : 0 + 4 : "Attack" : 0 + 16 : "Hold" : 0 + 32 : "Brutal" : 0 + ] + target(string) : "Next path target" + pathtarget(string) : "Action target" + wait(integer) : "Pause time" + message(string) : "Message" + speed(integer) : "Forward (jump)" : 200 + height(integer) : "Height (jump)" : 200 +] + + +@PointClass base(Appearflags, Targetname) size(-8 -8 -8, 8 8 8) = misc_fire_sparker : "Spark generator (triggered)" +[ + spawnflags(Flags) = + [ + 1 : "Fireball" : 0 + ] + delay(integer) : "Lifetime (0 for infinite)" : 0 +] + +// place teleporter units 10 units into a brush to get rid of teleport pad +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-32 -32 -24, 32 32 -16) = misc_teleporter : "Teleporter" +[ + spawnflags(Flags) = + [ + 1 : "No model" : 0 + 2 : "Random in deathmatch" : 0 + 4 : "Start off" : 0 + 8 : "Multi dest" : 0 + ] + target(string) : "Teleport Destination" +] +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-32 -32 -24, 32 32 -16) = misc_teleporter_dest : "Teleport Destination" [] +// H2 - Check +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-32 -32 -24, 32 32 -16) = misc_magic_portal : "Magic Portal" +[ + spawnflags(Flags) = + [ + 1 : "Start off" : 0 + ] + count(integer) : "Closes after this many seconds if greater than 0" + style(Choices) : "Style" : 0 = + [ + 0 : "Blue" + 1 : "Red" + 2 : "Green" + ] +] + +// H2 +@PointClass base(Appearflags, Targetname, Target) color(255 0 0) size(-32 -32 -24, 32 32 -16) = misc_remote_camera : "Remote Camera" +[ + spawnflags(Flags) = + [ + 1 : "Only for activator" : 0 + 2 : "Scripted camera (follow pathtarget?)" : 0 + 4 : "Don't delete camera" : 0 + ] + pathtarget(string) : "Owner entity (optional)" + delay(integer) : "Delay" +] + +@SolidClass base(Appearflags) = misc_update_spawner : "Updates level spawn point to trigger's position. Relevant for teleport spell." [] + + +// +// Monsters! +// + + +@BaseClass base(Appearflags, Target, Targetname) color(255 128 0) size(-16 -16 -24, 16 16 32) = Monsters +[ + spawnflags(Flags) = + [ + 1 : "Ambush" : 0 + 2 : "Trigger spawn" : 0 + 128 : "Fixed position" : 0 + 8192 : "Wander" : 0 : "Monster will wander around aimlessly (but follows buoys). May not work with all monsters" + 16384 : "Melee lead" : 0 : "Monster will tryto cut you off when you're running and fighting him, works well if there are a few monsters in a group, half doing this, half not" + 32768 : "Stalk" : 0 : "Monster will only approach and attack from behind- if you're facing the monster it will just stand there. Once the monster takes pain, however, it will stop this behaviour and attack normally" + 65536 : "Coward" : 0 :"Monster starts off in flee mode- runs away from you when woken up" + ] + combattarget(target_destination) : "Point combat target" + deathtarget(target_destination) : "Entity to trigger at death" + killtarget(target_destination) : "Entity to remove at death" + item(string) : "Spawn Item" +//h2 + mintel(integer) : "Intelligence" : 0 : "How many buoys away an enemy has to be for it to give up. Different monsters have different defaults." + scale(integer) : "Scale" + bypass_missile_chance(integer) : "Chance to not fire missile (0-100)" : 0 : "Chance that a monster will NOT fire it's ranged attack, even when it has a clear shot. This, in effect, will make the monster come in more often than hang back and fire." + jump_chance(integer) : "Jump chance (0-100)" : 0 : "Every time the monster has the opportunity to jump, what is the chance (out of 100) that he will." + melee_range(integer) : "Melee range" : 0 : "How close the player has to be, maximum, for the monster to go into melee. If zero, the monster will never melee. If negative, the monster will try to keep this distance from the player. If the monster has a backup, he'll use it if too clode, otherwise, a negative value here means the monster will just stop running at the player at this distance." + missile_range(integer) : "Maximum distance of enemy to fire missile" + wakeup_distance(integer) : "Wakeup distance" + homebuoy(target_destination) : "Buoy to seek without enemy" + pain_target(target_destination) : "Target used when first hurt" + wakeup_target(target_destination) : "Target used when first alerted" +] + + +@PointClass base(Monsters) size(-16 -16 -32, 16 16 48) = monster_assassin : "Assassin" +[ + spawnflags(flags) = + [ + 8 : "Forward jump ambush" : 0 : "Jump out front or back when triggered (depending on whether player is in front or behind him" + 16 : "Don't cloak" + 32 : "Don't teleport" + 64 : "Cinematic" + 131072 : "Trigger spawn, teleports when activated" + 262144 : "Start as shadow" : 0 : "Start as a shadow and decloak when wakes up" + 524288 : "Side jump ambush" : 0 : "Jump out to left or right (depending on which side of the assassin the player is)" + 1048576 : "Teleport dodge" : 0 : "Can use teleporting to dodge attacks" + ] + health(integer) : "Health" : 250 +] +@PointClass base(Monsters) = monster_bee : "Bee (unfinished)" [] +@PointClass base(Monsters) = monster_chicken : "Chicken" [] +@PointClass base(Monsters) size(-24 -24 -64, 24 24 16) = monster_elflord : "Celestial Watcher" +[ + health(integer) : "Health" : 2250 +] +@PointClass base(Monsters) size(-25 -25 -14, 25 25 14) = monster_fish : "Fish" +[ + health(integer) : "Health" : 50 +] +@PointClass base(Monsters) size(-20 -20 -0, 20 20 32) = monster_gkrokon : "Gkrokon" +[ + spawnflags(flags) = + [ + 131072 : "Resting" + ] + health(integer) : "Health" : 70 +] +@PointClass base(Monsters) size(-16 -16 0, 16 16 32) = monster_gorgon : "Gorgon" +[ + spawnflags(flags) = + [ + 4 : "Eating" + 8 : "Fast" + ] + health(integer) : "Health" : 100 +] +//@PointClass base(monster_gorgon) size(-16 -16 -0, 16 16 32) = monster_gorgon_leader : "Gorgon Leader" [] +@PointClass base(Monsters) size(-16 -16 -12, 16 16 12) = monster_harpy : "Harpy" +[ + spawnflags(flags) = + [ + 4 : "Perched" : 0 : "Will watch player until get too close or get behind the harpy" + 8 : "Circling" + ] + health(integer) : "Health" : 60 +] +@PointClass base(Monsters) size(-24 -24 0, 24 24 72) = monster_high_priestess : "High Priestess" +[ + health(integer) : "Health" : 2500 +] +@PointClass base(Monsters) = monster_imp : "Imp (unfinished)" [] +@PointClass base(Monsters) size(-24 -24 -50, 24 24 40) = monster_morcalavin : "Morcalavin" [] +@SolidClass base(Appearflags) = obj_morcalavin_barrier : "Morcalavin's barrier. Invisible & non-blocking until used." [] +@PointClass base(Monsters) size(-36 -36 0, 36 36 96) = monster_mssithra : "Mssithra" +[ + health(integer) : "Health" : 2250 +] +@PointClass base(Monsters) = monster_nothing : "Nothing" [] +@PointClass base(Monsters) size(-16 -16 -24, 16 16 16) = monster_ogle : "Ogle" +[ + spawnflags(choices) = + [ + 0 : "Random type" + 1 : "PUSHING" + 2 : "PICK_UP" + 4 : "PICK_DOWN" + 8 : "CHISEL_UP" + 16 : "CHISEL_DOWN" + 32 : "HAMMER_UP" + 64 : "HAMMER_DOWN" + 128 : "SONG_LEADER" + 8448 : "Cinematic" + ] +] +@PointClass base(Monsters) size(-17 -25 -1, 22 12 63) = monster_palace_plague_guard : "Plague Guard" [] +@PointClass base(monster_palace_plague_guard) = monster_palace_plague_guard_invisible : "Invisible Plague Guard" [] +@PointClass base(Monsters) size(-17 -25 -1, 22 12 63) = monster_plagueElf : "Elf" +[ + spawnflags(flags) = + [ + 8 : "Cinematic" + 16 : "Missile" + ] + health(integer) : "Health" : 50 +] +@PointClass base(Monsters) size(-16 -16 -0, 16 16 32) = monster_rat : "Rat" +[ + spawnflags(flags) = + [ + 4 : "Eating" + ] + health(integer) : "Health" : 10 +] +@PointClass base(monster_rat) = monster_rat_giant : "Giant Rat" +[ + health(integer) : "Health" : 40 +] +@PointClass base(Monsters) size(-16 -16 -0, 16 16 32) = monster_spreader : "Spreader" +[ + health(integer) : "Health" : 250 +] +@PointClass base(Monsters) size(-24 -24 -34, 24 24 34) = monster_seraph_guard : "Seraph Guard" +[ + spawnflags(flags) = + [ + 4 : "Golem" + ] + health(integer) : "Health" : 300 +] +@PointClass base(Monsters) size(-24 -24 -34, 24 24 34) = monster_seraph_overlord : "Seraph Overlord" +[ + health(integer) : "Health" : 250 +] +@PointClass base(Monsters) size(-16 -16 -32, 16 16 26) = monster_ssithra : "Plague Ssithra" +[ + spawnflags(flags) = + [ + 8 : "Jump out of water when woken up or used" + 16 : "Spin around when woken up or used" + 32 : "Tougher" + 64 : "Clothed, shoot explosive tip proj's" + ] + health(integer) : "Health" : 125 +] +@PointClass base(Monsters) size(-16 -16 -32, 16 16 32) = monster_tcheckrik_female : "Female Tcheckrik" +[ + spawnflags(flags) = + [ + 8 : "Cinematic" + 16 : "" + 32 : "Alternate projectile attack" + ] + health(integer) : "Health" : 200 +] +@PointClass base(Monsters) size(-16 -16 -32, 16 16 32) = monster_tcheckrik_male : "Male Tcheckrik" +[ + spawnflags(flags) = + [ + 8 : "Cinematic" + 16 : "Beast fodder" + 32 : "Yellowjacket type" + ] + health(integer) : "Health" : 200 +] +@PointClass base(Monsters) size(-40 -40 -75, 40 40 75) = monster_tcheckrik_mothers : "Tcheckrik Mother" [] +@PointClass base(Monsters) size(-100 -100 -36, 100 100 150) = monster_trial_beast : "Trial Beast" +[ + health(integer) : "Health" : 7000 +] + + +// using a "wait" value of -1 on a path corner causes a func_train to go silent between +// itself and the next path corner when the train is restarted. The train's sound will +// resume as soon as it reaches a path corner with a "wait" value other than -1 +@PointClass base(Appearflags, Targetname) color(128 76 0) size(-8 -8 -8, 8 8 8) = path_corner : "Path marker" +[ + spawnflags(Flags) = + [ + 1 : "Teleport" : 0 + ] + angles(string) : "Rotation angles (XYZ)" + noise(string) : "Sound when train touches (path/file.wav)" + target(target_destination) : "Next path target" + pathtarget(target_destination) : "Event to trigger" + wait(choices) : "Wait" : 0 = + [ + -1 : "Wait for retrigger" + -3 : "Explode train" + ] +] + +// "target" doesn't work (for now)...a separate trigger is needed +@PointClass base(Appearflags, Targetname, Target) color(128 76 9) size(-8 -8 -8, 8 8 8) = point_combat : "1st point of combat" +[ + spawnflags(Flags) = + [ + 1 : "Hold (monster stays in place)" : 0 + ] + pathtarget(target_destination) : "Event to trigger when monster touches" +] + +// set "map" value to "mapname$playername" where playername equals +// the targetname of a corresponding info_player_start in the +// next map. To play a cinematic before starting the level, the +// "map" value should be "cinemeatic.cin+mapname$playername". Note +// that a playername is not required if the corresponding info_player_start +// doesn't have a targetname. If you want this to be designated as the last +// level of a unit, place an asterix (*) before the map name. +@PointClass base(Appearflags, Targetname, Target) color(0 255 0) size(-8 -8 -8, 8 8 8) = target_changelevel : "Change level" +[ + map(string) : "'Next map'$'Player start targetname' - use * before map name to end unit" +] + +@PointClass base(Appearflags, Targetname, Target) color(128 128 128) size(-8 -8 -8, 8 8 8) = target_crosslevel_trigger : "Cross-level trigger" +[ + spawnflags(Flags) = + [ + 1 : "Trigger 1" : 0 + 2 : "Trigger 2" : 0 + 4 : "Trigger 3" : 0 + 8 : "Trigger 4" : 0 + 16 : "Trigger 5" : 0 + 32 : "Trigger 6" : 0 + 64 : "Trigger 7" : 0 + 128 : "Trigger 8" : 0 + ] + killtarget(string) : "Kill Target" + message(string) : "Message" + delay(integer) : "Trigger delay" +] + +@PointClass base(Appearflags, Targetname, Target) color(128 128 128) size(-8 -8 -8, 8 8 8) = target_crosslevel_target : "Cross-level trigger" +[ + spawnflags(Flags) = + [ + 1 : "Trigger 1" : 0 + 2 : "Trigger 2" : 0 + 4 : "Trigger 3" : 0 + 8 : "Trigger 4" : 0 + 16 : "Trigger 5" : 0 + 32 : "Trigger 6" : 0 + 64 : "Trigger 7" : 0 + 128 : "Trigger 8" : 0 + ] + killtarget(string) : "Kill Target" + delay(integer) : "Trigger delay (if activated)" : 1 +] + +@PointClass base(Appearflags, Targetname) color(0 255 0) size(-8 -8 -8, 8 8 8) = target_earthquake : "Level wide earthquake" +[ + speed(integer) : "Severity of quake" : 200 + count(integer) : "Duration" : 5 +] + +@PointClass base(Appearflags, Targetname) color(0 255 0) size(-8 -8 -8, 8 8 8) = target_explosion : "Explosion" +[ + delay(integer) : "Delay before explosion" + dmg(integer) : "Radius damage" : 0 +] + +@PointClass base(Appearflags, Targetname, Target) color(0 128 204) size(-8 -8 -8, 8 8 8) = target_lightramp : "Light ramp" +[ + spawnflags(Flags) = + [ + 1 : "Toggle" : 0 + ] + speed(integer) : "Speed" + message(string) : "Start/end light level (a-z)" +] + +@PointClass base(Appearflags, Targetname) color(0 0 255) size(-8 -8 -8, 8 8 8) = target_splash : "Splash effect (triggered)" +[ + sounds(choices) : "Splash type" = + [ + 1 : "Sparks" + 2 : "Blue water" + 3 : "Brown water" + 4 : "Slime" + 5 : "Lava" + 6 : "Blood" + ] + count(integer) : "Number of pixels" + dmg(integer) : "Radius damage (useful for lava/sparks)" +] + +// eye candy... Particles #2 (style 22) is quite cool +@PointClass base(Appearflags, Targetname) color(0 255 0) size(-8 -8 -8, 8 8 8) = target_temp_entity : "Triggered temp entity" +[ + style(choices) : "Style" : 22 = + [ + 20 : "Green Fireball" + 21 : "Particles #1" + 22 : "Particles #2" + ] +] + +// +// Triggers +// + +@BaseClass base(Appearflags, Targetname, Target) color(128 128 128) = Trigger +[ + killtarget(string) : "Kill Target" + delay(integer) : "Time before triggering" + message(string) : "Message (levelmsg.txt index)" + text_msg(string) : "Message (raw string)" +] + +@SolidClass base(Appearflags, Targetname, Target) = choose_CDTrack : "Sets CD track" +[ + spawnflags(Flags) = + [ + 1 : "Don't loop" + ] + style(integer) : "Track number" +] + +@PointClass base(Appearflags, Target) color(128 128 128) size(-8 -8 -8, 8 8 8) = trigger_always : "Trigger automatically fired by world" +[ + killtarget(string) : "Kill Target" + delay(integer) : "Time before triggering" +] + +@PointClass base(Appearflags, Targetname, Target) color(128 128 128) size(-8 -8 -8, 8 8 8) = trigger_counter : "Counter" +[ + spawnflags(Flags) = + [ + 1 : "No Message" : 0 + ] + killtarget(string) : "Kill Target" + count(integer) : "Count before trigger" : 2 +] + +@SolidClass base(Appearflags, Targetname) = trigger_farclip : "Changes the console variable r_farclipdist. +If the current value is default, it sets it to the trigger’s key value. +If set to the trigger’s key value, it sets it back to default. +Do not have teleport points, or start spots of any kind inside or inbetween this trigger." +[ + scale(integer) : "Distance" : 4096 +] + +@PointClass base(Appearflags, Targetname, Target) color(76 25 153) = trigger_elevator : "Elevator trigger" [] + +@SolidClass base(Appearflags, Targetname) = trigger_fogdensity : "Sets r_fog_density and fog color" +[ + target(string) : "Fog density (.01 - .0001)" + color(string) : "RGB values" +] + +@SolidClass base(Appearflags) color(128 128 128) = trigger_gravity : "Change gravity" +[ + gravity(integer) : "Gravity (standard = 1.0)" : 1 +] + +@PointClass base(Appearflags, Targetname, Target) color(128 128 128) size(-8 -8 -8, 8 8 8) = trigger_key : "Triggers with key" +[ + killtarget(string) : "Kill target" + item(string) : "Item classname" : "item_tavern_key" +] + +// H2 + +@SolidClass base(Appearflags, Targetname, Target) = trigger_Damage : "Damage" +[ + spawnflags(flags) = + [ + 1 : "Start off" + 2 : "Toggle" + 4 : "Silent" + 8 : "No protection" + 16 : "Slow (once per second)" + ] + dmg(integer) : "Damage" : 5 +] +@SolidClass base(Trigger) = trigger_Deactivate : "Deactivates target" [] +@SolidClass base(Trigger) = trigger_Activate : "Activates target" [] +@SolidClass base(Trigger) = trigger_endgame : "Ends game" [] +@SolidClass base(Appearflags, Targetname) = trigger_goto_buoy : "Send monster to buoy" +[ + spawnflags(flags) = + [ + 1 : "Touchable" + 2 : "Ignore enemy" : 0 : "Monster will ignore his enemy until he gets to his target buoy (or until attacked or woken up some other way)" + 4 : "Teleport to buoy (safe)" : 0 : "Make monster teleport to target buoy only if there is nothing there and the player cannot see the monster and/or desination buoy" + 8 : "Teleport to buoy (unsafe)" : 0 : "Same as TeleportSafe, but ignores whether or not the player can see the monster and/or desination buoy" + 16 : "Make monster fixed" + 32 : "Make monster forget enemy" + 64 : "Make monster forget and wander" + ] + pathtarget(string) : "Buoy for monster to go to" + target(target_destination) : "Monster to send to buoy if triggered" + delay(integer) : "Delay before sending monster to buoy" + wait(integer) : "Time between uses" +] +@SolidClass base(Trigger) = trigger_lightning : "Triggers lightning bolt" +[ + delay(integer) : "Duration of lightning (0-25.5)" + materialtype(choices) = + [ + 0 : "Blue" + 1 : "Red" + ] + style(integer) : "Bolt width" + wait(integer) : "Wait" : 10 + target(target_source) : "Ending point" +] +@SolidClass base(Appearflags) = trigger_mappercentage : "Map percentage" +[ + count(integer) : "Count" +] +@SolidClass base(Trigger) = trigger_mission_give : "Gives mission objectives" +[ + message(string) : "Message (index in strings.txt)" +] +@SolidClass base(Trigger) = trigger_mission_take : "Removes mission objectives" +[ + spawnflags(flags) = + [ + 16 : "Take objective 1" + 32 : "Take objective 2" + ] +] +@SolidClass base(Appearflags, Targetname, Target) = trigger_playerpushbutton : "Player push button" [] +@SolidClass base(Appearflags, Targetname, Target) = trigger_playerpushlever : "Player Push lever" [] +@SolidClass base(Appearflags, Targetname, Target) = trigger_playerusepuzzle : "Player can use puzzle items within this entity" +[ + spawnflags(flags) = + [ + 16 : "Don't show inventory bar, don't take puzzle piece" + 32 : "Multiple use" + ] + target(target_destination) : "trigger_puzzle to use" +] +@PointClass base(Appearflags, Targetname, Target) = trigger_puzzle : "Relay that requires puzzle piece" +[ + spawnflags(flags) = + [ + 1 : "No text" + 2 : "Don't take item" + ] + item(string) : "Item" +] +@PointClass base(Trigger) = trigger_quake : "Earthquake" +[ + count(integer) : "Maximum pixels to shake screen" : 20 + style(choices) : "Shake direction" : 7 = + [ + 1 : "Lateral" + 2 : "Vertical" + 4 : "Depth" + 7 : "All directions" + ] + time(integer) : "Duration in seconds (0-12.8)" + wait(integer) : "Wait" : 10 +] +@SolidClass base(Appearflags, Targetname, Target) = trigger_quit_to_menu : "Quit to menu" [] +@SolidClass base(Appearflags) color(128 128 128) = trigger_MonsterJump : "Makes monsters jump" +[ + speed(integer) : "Speed thrown forward" : 200 + height(integer) : "Height thrown upward" : 200 +] +@PointClass base(Trigger) color(128 128 128) = trigger_relay : "Relay trigger" [] +@SolidClass base(Trigger) = trigger_once : "Single fire trigger" +[ + spawnflags(Flags) = + [ + 1 : "Monster" : 0 + 2 : "Not Player" : 0 + 4 : "Triggered" : 0 + 8 : "Anything can activate" + ] + sounds(choices) : "Sounds" : 0 = + [ + 1 : "Secret (not functional)" + 2 : "Silence" + 3 : "Chat sound" + ] +] +@SolidClass base(Trigger) = trigger_multiple : "Multiple fire trigger" +[ + spawnflags(Flags) = + [ + 1 : "Monster" : 0 + 2 : "Not Player" : 0 + 4 : "Triggered" : 0 + 8 : "Anything can activate" + ] + sounds(choices) : "Sounds" : 0 = + [ + 1 : "Secret (not functional)" + 2 : "Silence" + 3 : "Chat sound" + ] + wait(integer) : "Seconds between triggers" : 0 +] +@SolidClass base(Appearflags) color(128 128 128) = trigger_push : "Push trigger" +[ + spawnflags(Flags) = + [ + 1 : "Push Once" : 0 + ] + speed(integer) : "Speed of push" : 500 + zangle(integer) : "Upwards direction (0 is straight up, 180 is straight down)" +] + +// +// Characters +// + +@BaseClass base(Appearflags, Targetname) color(76 76 255) size(-16 -16 -24, 16 16 32) = character +[ + spawnflags(flags) = + [ + 1 : "Invisible" + ] +] + +@PointClass base(character) size(-17 -25 -32, 22 12 32) = character_corvus1 : "cinematic corvus for the torture victim" [] +@PointClass base(character_corvus1) = character_corvus2 : "cinematic Corvus for the celestial watcher scene" [] +@PointClass base(character_corvus1) = character_corvus3 : "cinematic Corvus for the high priestess scene" [] +@PointClass base(character) size(16 -16 -34, 16 16 25) = character_corvus4 : "cinematic Corvus for the Scout scene" [] +@PointClass base(character_corvus4) = character_corvus5 : "cinematic Corvus for the Dranor scene" [] +@PointClass base(character_corvus4) = character_corvus6 : "cinematic Corvus for the Dranor scene" [] +@PointClass base(character_corvus1) = character_corvus7 : "cinematic corvus for the Morcalavin scene" [] +@PointClass base(character_corvus1) = character_corvus8 : "cinematic corvus for the Siernan scenes" [] +@PointClass base(character_corvus1) = character_corvus9 : "cinematic corvus for the T'chekrik scenes" [] +@PointClass base(character) size(-17 -25 -32, 22 12 32) = character_dranor : "Dranor" [] +@PointClass base(character) size(-24 -24 -78, 24 24 16) = character_elflord : "Celestial Watcher" [] +@PointClass base(character) size(-24 -24 -36, 24 24 36) = character_highpriestess : "High Priestess" [] +@PointClass base(character_highpriestess) = character_highpriestess2 : "High Priestess" [] +@PointClass base(character) size(-24 -24 -50, 24 24 50) = character_morcalavin : "Morcalavin" [] +@PointClass base(character) size(-10 -10 -20, 10 10 20) = character_siernan1 : "Siernan standing" +[ + spawnflags(flags) = + [ + 4 : "Leaning" + ] +] +@PointClass base(character) size(-17 -25 0, 22 12 16) = character_siernan2 : "Siernan laying down" [] +@PointClass base(character) size(-26 -16 -13, 26 16 13) = character_ssithra_scout : "Ssithra scout" [] +@PointClass base(character) size(-40 -16 -2, 40 16 2) = character_ssithra_victim : "Ssithra torture victim" [] +@PointClass base(character) size(-4 -8 -12, 4 8 12) = character_tome : "Tome of Power" [] + +//Env - fix +@BaseClass base(Appearflags, Target, Targetname) color(76 76 255) size(-8 -8 -8, 8 8 8) = Env +[ +] + +@PointClass base(Env) = env_bubbler : "Bubbler" +[ + count(integer) : "Bubbles per minute" : 120 +] +@SolidClass base(Env) = env_dust : "Dust (triggered)" +[ + count(integer) : "Number of rocks (max 16)" +] +@PointClass base(Env) = env_fire : "Flame effect. Does not emit light" +[ + spawnflags(flags) = + [ + 8 : "Start off" + 16 : "Moveable" + 32 : "Light attached" + ] + scale(integer) : "Scale (0-8)" +] +@PointClass base(Env) = env_mist : "Mist" +[ + scale(integer) : "Scale" +] +@PointClass base(Env) = env_smoke : "Smoke" +[ + angle(integer) : "Puff move direction" : 0 + scale(integer) : "Puff size (1-8)" : 1 + speed(integer) : "Puff speed (10-2500)" : 100 + distance(integer) : "Distance before puff disappears (1-255)" : 100 + wait(integer) : "Time between puffs (1-255)" : 5 +] +@PointClass base(Env) = env_sun1 : "Places two suns in the world and attaches a lens flare to them. One sun is blue, the other is yellow" [] +@PointClass base(Env) = env_water_drip : "Water drip" +[ + spawnflags(flags) = + [ + 1 : "Yellow" + ] + count(integer) : "Drips per minute" : 20 +] +@PointClass base(Env) = env_water_fountain : "Fountain" +[ + spawnflags(flags) = + [ + 1 : "Start off" + ] + angles(string) : "XYZ velocity of particles" + delay(integer) : "Distance from emitter to ground (max 256)" +] +@PointClass base(Env) = env_waterfall_base : "waterfall base" +[ + angles(string) : "X radius, yaw, Y radius" +] + +// H2: Shrines +@BaseClass base(Appearflags, Target, Targetname) color(76 76 255) size(-8 -8 -8, 8 8 8) = Shrine +[ + spawnflags(Flags) = + [ + 1 : "Permanent" + ] +] + +@SolidClass base(Shrine) = shrine_random : "Random Shrine" [] +@SolidClass base(Shrine) = shrine_armor : "Armor Shrine" [] +@SolidClass base(Shrine) = shrine_heal : "Health Shrine" [] +@SolidClass base(Shrine) = shrine_light : "Light Shrine" [] +@SolidClass base(Shrine) = shrine_mana : "Mana Shrine" [] +@SolidClass base(Shrine) = shrine_reflect : "Reflect Shrine" [] +@SolidClass base(Shrine) = shrine_staff : "Staff Shrine" [] +@SolidClass base(Shrine) = shrine_powerup : "Powerup Shrine" [] +@SolidClass base(Shrine) = shrine_ghost : "Ghost Shrine" [] +@SolidClass base(Shrine) = shrine_armor_gold : "Gold Armor Shrine" [] +@SolidClass base(Shrine) = shrine_lung : "Lung Shrine" [] +@SolidClass base(Shrine) = shrine_speed : "Speed Shrine" [] + +@BaseClass base(Appearflags, Target, Targetname) color(76 76 255) size(-8 -8 -8, 8 8 8) = object +[ + spawnflags(Flags) = + [ + 1 : "Invulnerable" + 8 : "Not pushable" + ] + scale(integer) : "Scale" +] + +@PointClass base(object) size(-26 -38 -38, 26 38 38) = obj_shrine : "Shrine model. Target with a matching shrine_(style) trigger brush." +[ + style(choices) : "Type of shrine" : 1 = + [ + 0 : "heal" + 1 : "mana" + 2 : "lungs" + 3 : "light" + 4 : "powerup" + 5 : "armor" + 6 : "gold armor" + 7 : "random" + 8 : "reflection" + 9 : "staff" + 10 : "ghost" + 11 : "speed" + ] +] + +@PointClass base(object) size(0 -19 -24, 4 19 24) = obj_andwallhanging : "Circular Andorian wall hanging" [] +@PointClass base(object) size(-8 -44 -296, 8 44 0) = obj_banner : "Banner" +[ + skinnum(choices) = + [ + 0 : "Blue" + 1 : "Red" + ] +] +@PointClass base(object) size(-8 -28 -30, 8 28 30) = obj_banneronpole : "Banner on Pole" +[ + spawnflags(Flags) = + [ + 1 : "Invulnerable" + 2 : "Animate (flutter)" + ] +] +@PointClass base(object) size(-12 -12 -19, 12 12 19) = obj_barrel : "Barrel" +[ + spawnflags(Flags) = + [ + 1 : "Invulnerable" + 2 : "" + 4 : "Exploding" + 8 : "Not pushable" + ] + killtarget(string) : "Killtarget" +] +@PointClass base(object) size(-11 -12 -18, 11 12 18) = obj_barrel_metal : "Metal barrel" [] +@PointClass base(object) size(-11 -12 -18, 11 12 18) = obj_barrel_explosive : "Explosive barrel. Use barrel with spawnflags 4 instead" [] +@PointClass base(object) size(-13 -13 -21, 13 13 21) = obj_basket : "Basket" [] +@PointClass base(object) size(-10 -21 -10, 10 21 10) = obj_bench : "Bench" [] +@PointClass base(object) size(-35 -35 -50,35 35 50) = obj_bigcrystal : "Rotating crystal" +[ + speed(integer) : "Speed of rotation" +] +@PointClass base(object) size(-20 -33 -52, 20 33 52) = obj_biotank : "Bio Tank" +[ + scale(integer) : "Scale" + style(choices) = + [ + 0 : "Empty" + 1 : "ET's head" + 2 : "Hairless critter" + 3 : "Three fish" + 4 : "Wasp" + ] +] +@PointClass base(object) = obj_bloodsplat : "Blood splat" [] +@PointClass base(object) size(-8 -16 -2, 8 16 2)= obj_bookopen : "Open Book" [] +@PointClass base(object) size(-8 -8 -2, 8 8 2) = obj_bookclosed : "Closed book standing up" [] +@PointClass base(object) size(-3 -3 -7, 3 3 7) = obj_bottle1 : "Bottle" [] +@PointClass base(object) size(-2 -2 -25, 2 2 25) = obj_broom : "Broom" [] +@PointClass base(object) size(-8 -8 -9, 8 8 10) = obj_bucket : "Bucket" [] +@PointClass base(object) size(-34 -34 -19, 34 34 19) = obj_bush1 : "Bush" [] +@PointClass base(object) size(-56 -56 -40, 56 56 40) = obj_bush2 : "Bush 2" [] +@PointClass base(object) size(-18 -18 -44, 18 18 44) = obj_cactus : "Cactus" [] +@PointClass base(object) size(-14 -14 -32, 18 18 32) = obj_cactus3 : "Cactus 3" [] +@PointClass base(object) size(-11 -11 -11, 11 11 11) = obj_cactus4 : "Cactus 4 (triggerable)" [] +@PointClass base(object) size(-22 -22 -10, 22 22 10) = obj_cauldron : "Cauldron" +[ + spawnflags(Flags) = + [ + 1 : "Invulnerable" + 2 : "Animate" + 3 : "" + 4 : "Not pushable" + ] +] +@PointClass base(object) size(-12 -8 -26, 12 8 26) = obj_chair1 : "Chair (wood)" [] +@PointClass base(object) size(-18 -29 -30, 18 29 30) = obj_chair2 : "Chair (wood, slanted)" [] +@PointClass base(object) size(-14 -21 -28, 14 21 28) = obj_chair3 : "Chair (stone)" [] +@PointClass base(object) size(-10 -18 -19, 10 18 19) = obj_chest1 : "Chest (opens when triggered)" [] +@PointClass base(object) size(-14 -17 -9, 14 17 9) = obj_chest2 : "Chest (mines)" [] +@PointClass base(object) size(-10 -17 -6, 10 17 6) = obj_chest3 : "Chest (mines, closed)" [] +@PointClass base(object) size(-15 -40 -8, 15 40 8) = obj_choppeddude : "Lying chopped corpse" [] +@PointClass base(object) size(-6 -6 -2, 6 6 2) = obj_claybowl : "Clay bowl" [] +@PointClass base(object) size(-15 -15 -24, 15 15 24) = obj_clayjar : "Clay jar" [] +@PointClass base(object) = obj_cocoon : "Hanging cocoon" [] +@PointClass base(object) = obj_cocoonopen : "Hanging cocoon" [] +@PointClass base(object) size(-8 -4 0, 8 4 20) = obj_cog1 : "Cog (triggerable)" [] +@PointClass base(object) size(-30 -12 0, 30 12 5) = obj_corpse1 : "Plague Elf corpse" +[ + style(choices) : "Position" = + [ + 0 : "Arms above head" + 1 : "On side" + 2 : "Arm over face" + 3 : "Arms to side" + 4 : "Skewered" + ] +] +@PointClass base(obj_corpse1) = obj_corpse2 : "Plague Elf corpse (alternate skin)" [] +@PointClass base(obj_corpse1) = obj_corpse_ssithra : "Plague Ssithra corpse" +[ + style(choices) : "Skin" = + [ + 0 : "" + 1 : "" + 2 : "" + ] +] +@PointClass base(object) size(-30 -12 0, 30 12 5) = obj_dying_elf : "Dying elf" +[ + style(choices) : "Skin" = + [ + 0 : "" + 1 : "" + ] +] +@PointClass base(object) size(-4 -10 -1, 4 10 1) = obj_eggpan : "Flat pan" [] +@PointClass base(object) size(-13 -13 -18, 13 13 18) = obj_eyeball_jar : "Jar of joy" [] +@PointClass base(object) size(0 -76 -86, 136 76 86) = obj_fishhead1 : "Fish head fountain" +[ + spawnflags(flags) = + [ + 1 : "No drip" + ] +] +@PointClass base(object) size(0 -110 -118, 136 110 118) = obj_fishhead2 : "Fish head fountain 2" +[ + spawnflags(flags) = + [ + 1 : "No drip" + ] +] +@PointClass base(object) size(-14 -28 -13, 14 28 13) = obj_fishtrap : "Fish trap" [] +@PointClass base(object) size(-18 -18 -12, 18 18 12) = obj_firepot : "Firepot" [] +@PointClass base(object) size(-8 -8 0, 8 8 60) = obj_flagonpole : "Flag on pole" [] +@PointClass base(object) size(-8 -8 -35, 8 8 35) = obj_floor_candelabrum : "Floor candelbrum. Does not emit light" [] +@PointClass base(object) size(-52 -34 -48, 52 34 48) = obj_fountain_fish : "Two-headed fish fountain. Water FX not included" [] +@PointClass base(object) size(-1 -3 -10, 1 3 10) = obj_frypan : "Hanging pan" [] +@PointClass base(object) size(-18 -38 -9, 18 38 1) = obj_gorgonbones : "Gorgon bones" [] +@PointClass base(object) size(-8 -9 -13, 8 9 13) = obj_gascan : "Gas can" [] +@PointClass base(object) size(-8 -8 -10, 8 8 10) = obj_grass : "Grass clump" [] +@PointClass base(object) size(-8 -16 -34, 8 16 34) = obj_hanging_ogle : "Hanging Ogle" [] +@PointClass base(object) size(-3 -20 -55, 3 20 55) = obj_hangingdude : "Hanging dude" [] +@PointClass base(object) size(-4 -4 -13, 4 4 13) = obj_hivepriestessssymbol : "Hive Priestess symbol (triggered)" [] +@PointClass base(object) = obj_jawbone : "Fish jawbone" [] +@PointClass base(object) size( -6 -6 -6, 6 6 6) = obj_jug1 : "Jug" [] +@PointClass base(object) size(-8 -8 0, 8 8 10) = obj_kettle : "Kettle" [] +@PointClass base(object) size(-8 -8 -11, 8 8 11) = obj_lab_parts_container : "Body parts container" [] +@PointClass base(object) size(-8 -8 -5, 8 8 5) = obj_lab_tray : "Tray with heart and tools" [] +@PointClass base(object) size(-8 -8 -2, 8 8 2) = obj_larva : "Squirming larva" [] +@PointClass base(object) size(-6 -14 -6, 6 14 6) = obj_larvaegg : "Hive egg" [] +@PointClass base(object) size( -6 -7 -5, 6 7 5) = obj_larvabrokenegg : "Hive egg" [] +@PointClass base(object) size(-6 -14 -17, 6 14 17) = obj_lever1 : "Floor lever" [] +@PointClass base(object) size(-14 -14 -9, 14 14 9) = obj_lever2 : "Wooden wheel lever" [] +@PointClass base(object) size(-4 -6 -16, 4 6 16) = obj_lever3 : "Wall lever" [] +@PointClass base(object) size( -10 -26 -4, 10 26 4) = obj_metalchunk1 : "Metal chunk" [] +@PointClass base(obj_metalchunk1) = obj_metalchunk2 : "Metal chunk" [] +@PointClass base(obj_metalchunk1) = obj_metalchunk3 : "Metal chunk" [] +@PointClass base(object) size(-18 -29 -20, 18 29 20) = obj_minecart : "Full minecart" [] +@PointClass base(obj_minecart) = obj_minecart2 : "Empty minecart" [] +@PointClass base(obj_minecart) = obj_minecart3 : "Busted minecart" [] +@PointClass base(object) size(-4 -10 -40, 4 10 40) = obj_moss1 : "Moss 1" [] +@PointClass base(obj_moss1) = obj_moss2 : "Moss 2" [] +@PointClass base(obj_moss1) = obj_moss3 : "Moss 3" [] +@PointClass base(obj_moss1) = obj_moss4 : "Moss 4" [] +@PointClass base(obj_moss1) = obj_moss5 : "Moss 5" [] +@PointClass base(object) size(-25 -25 -4, 25 25 4) = obj_nest : "Nest" [] +@PointClass base(object) size(-12 -13 -2, 12 13 2) = obj_pick : "Pick" [] +@PointClass base(object) size(-11 -24 -7, 11 24 7) = obj_pipe1 : "Pipe (90* turn)" [] +@PointClass base(object) size(-6 -25 -4, 6 25 4) = obj_pipe2 : "Pipe (straight)" [] +@PointClass base(object) size(-14 -14 -12, 14 14 12) = obj_pipewheel : "Pipe shutoff valve" [] +@PointClass base(object) size(-8 -8 -24, 8 8 24) = obj_plant1 : "Plant" [] +@PointClass base(object) size(-20 -20 -10, 20 20 20) = obj_plant2 : "Plant" [] +@PointClass base(object) size(-8 -8 -12, 8 8 12) = obj_plant3 : "Plant" [] +@PointClass base(object) size(-3 -8 -8, 3 8 8) = obj_pot1 : "Hanging cooking pot" [] +@PointClass base(object) size(-7 -7 -3, 7 7 3) = obj_pot2 : "Flat cooking pot" [] +@PointClass base(object) size(-20 -20 -30, 20 20 30) = obj_pottedplant : "Potted plant" [] +@PointClass base(object) size(-13 -16 -41, 13 16 41) = obj_pushcart : "Push cart" [] +@PointClass base(object) size(-30 -28 -31, 30 28 31) = obj_queenchair : "Hive queen chair" [] +@PointClass base(object) size(-40 -56 -49, 40 56 49) = obj_queenthrone : "Hive queen throne" [] +@PointClass base(object) size(-2 -24 -20, 2 24 20) = obj_ring_plaque2 : "Rings mounted on wall plate" [] +@PointClass base(object) size(-12 -13 -4, 12 13 4) = obj_rocks1 : "Rock cluster" [] +@PointClass base(object) size(-9 -30 -4, 9 30 4) = obj_rocks2 : "Big rock" [] +@SolidClass base(object) = obj_rope : "Climbable rope. Requires origin brush (brush with ORIGIN content flag)" +[ + spawnflags(Flags) = + [ + 0 : "Rope" + 1 : "Vine" + 2 : "Chain" + 4 : "Tendril" + 8 : "Hanging chicken" + ] +] +@PointClass base(object) size(-20 -20 -14, 20 20 14) = obj_ropechain : "Rope chain" +[ + skinnum(choices) = + [ + 0 : "Rope" + 1 : "Chain" + ] +] +@PointClass base(object) size(-8 -8 -20, 8 8 20) = obj_shovel : "Shovel" [] +@PointClass base(object) size(-29 -4 -16, 29 4 16) = obj_sign1 : "Sign 1" +[ + style(choices) : "Style" = + [ + 0 : "Dragon" + 1 : "Steins" + 2 : "Fish" + ] +] +@PointClass base(object) size(-8 -18 -29, 8 18 29) = obj_sign4 : "Sign 4" +[ + style(choices) : "Style" = + [ + 0 : "Andorian" + 1 : "Tchekrik" + ] +] +@PointClass base(object) size( -10 -10 -47, 10 10 47) = obj_skullpole : "Skull pole" [] +@PointClass base(object) size(-32 -32 -200, 32 32 0) = obj_stalagmite1 : "Stalagmite" +[ + spawnflags(Flags) = + [ + 1 : "Dark skin" + ] +] +@PointClass base(obj_stalagmite1) size(-32 -32 -128, 32 32 0) = obj_stalagmite2 : "Stalagmite" [] +@PointClass base(obj_stalagmite1) = obj_stalagmite3 : "Stalagmite" [] +@PointClass base(object) size(-24 -24 -99, 24 24 99) = obj_stalactite1 : "Stalagtite" +[ + spawnflags(Flags) = + [ + 1 : "Drip water" + 2 : "Dark skin" + ] + count(integer) : "Drips per minute" : 20 +] +@PointClass base(obj_stalactite1) size(-60 -60 -64, 60 60 64) = obj_stalactite2 : "Stalagtite" [] +@PointClass base(obj_stalactite1) size(-23 -23 -98, 23 23 98) = obj_stalactite3 : "Stalagtite" [] +@PointClass base(object) size(-26 -16 -27, 26 16 27) = obj_statue_boulderfish : "Fish statue" [] +@PointClass base(object) size(-16 -16 0, 16 16 32) = obj_statue_corvus : "Corvus statue" [] +@PointClass base(object) size(-68 -22 -30, 68 22 30) = obj_statue_dolphin1 : "Dolphin statue on all fours" [] +@PointClass base(object) size(-17 -20 -70, 17 20 70) = obj_statue_dolphin2 : "Dolphin statue on wall turned right" [] +@PointClass base(obj_statue_dolphin2) = obj_statue_dolphin3 : "Dolphin statue on wall turned left" [] +@PointClass base(object) size(-63 -22 -37, 63 22 37) = obj_statue_dolphin4 : "Dolphin statue on two legs" [] +@PointClass base(object) size(-76 -28 -46, 76 28 46) = obj_statue_dragonhead : "Dragon head statue" [] +@PointClass base(object) size(-53 -33 -72, 53 33 72) = obj_statue_dragon : "Dragon statue" +[ + style(choices) = + [ + 0 : "Looking left" + 1 : "Looking right" + ] +] +@PointClass base(object) size(-63 -22 -37, 63 22 37) = obj_statue_duckbill1 : "" [] +@PointClass base(object) size(-67 -24 -50, 67 24 50) = obj_statue_duckbill2 : "" [] +@PointClass base(object) size(-100 -64 0, 64 64 128) = obj_statue_guardian : "Guardian statue" [] +@PointClass base(object) size(-10 -20 -24, 10 20 24) = obj_statue_saraphbust : "Seraph bust" [] +@PointClass base(object) size(-13 -16 -41, 13 16 41) = obj_statue_sariph : "Seraph statue" [] +@PointClass base(object) size(-22 -20 -57, 22 20 57) = obj_statue_sithraguard : "A statue of a sithra guard with spear extended. When used he gains a shield and pulls his arm back. Used with: item_puzzle_shield" [] +@PointClass base(object) size(-8 -12 -15, 8 12 15) = obj_statue_tchecktrik_bust : "A bust of a tchecktrik. When used a necklace appears around it's neck." +[ + style(choices) = + [ + 0 : "no necklace until used then necklace appears" + 1 : "necklace until used then necklace disappears" + ] +] +@PointClass base(object) size(-41 -11 -14, 41 11 14) = obj_statue_techeckriktomb : "Tchekrik laying down (triggerable)" [] +@PointClass base(object) size(-26 -40 -50, 26 40 50) = obj_statue_techeckrikleft : "Tcheckrik statue left (triggerable)" [] +@PointClass base(object) size(-26 -40 -50, 26 40 50) = obj_statue_techeckrikright : "Tcheckrik statue right (triggerable)" [] +@PointClass base(object) size(-2 -18 -3, 2 18 3) = obj_scroll : "Scroll" [] +@PointClass base(object) size(-80 -80 0, 80 80 100) = obj_seasonglobe : "Globe (triggerable)" [] +@PointClass base(object) size(-2 -2 -3, 2 2 3) = obj_stein : "Stein" [] +@PointClass base(object) size(-14 -14 -35, 14 14 40) = obj_spellbook : "Spell book that closes when triggered" [] +@PointClass base(object) size(0 -100 -48, 2 100 48) = obj_swampflat_top : "A flat poly to be used on the outer edge of swamp levels. Vegetation growing up." [] +@PointClass base(object) size(0 -100 -48, 2 100 48) = obj_swampflat_bottom : "A flat poly to be used on the outer edge of swamp levels. Vegetation growing down." [] +@PointClass base(object) size(-28 -54 -18, 28 54 18) = obj_table1 : "Table (wood)" [] +@PointClass base(object) size(-28 -54 -18, 28 54 18) = obj_table2 : "Table (stone)" [] +@PointClass base(object) size(-20 -22 -44, 20 22 44) = obj_throne : "Throne" [] +@PointClass base(object) size(-2 -5 -2, 2 5 2) = obj_tapper : "Keg tapper" [] +@PointClass base(object) size(-21 -43 -94, 21 43 94) = obj_torture_bed : "Bed of spikes" [] +@PointClass base(object) size(-18 -18 -49, 18 18 49) = obj_torture_ironmaiden : "Iron maiden (closes when used)" [] +@PointClass base(object) size(-22 -46 -19, 22 46 19) = obj_torture_rack : "Torture rack" [] +@PointClass base(object) size(-46 -14 -14, 46 14 14) = obj_torture_table : "Torture table" +[ + style(choices) = + [ + 0 : "Down" + 1 : "Upright" + ] +] +@PointClass base(object) size(-2 -4 -6, 2 4 6) = obj_torture_wallring : "Hanging ring" [] +@PointClass base(object) size(-100 -100 -120, 100 100 120) = obj_tree : "Tree" [] +@PointClass base(object) size(-50 -50 -286, 50 50 286) = obj_tree2 : "Tree (swamp)" [] +@PointClass base(object) size(-50 -50 -286, 50 50 286) = obj_tree3 : "Tree with roots" [] +@PointClass base(object) size(-46 -46 -340, 46 46 340) = obj_treetall : "Tree (tall)" [] +@PointClass base(object) size(-176 -176 -125, 176 176 125) = obj_treetop : "Tree canopy" [] +@PointClass base(object) size(-24 -62 -35, 24 62 35) = obj_treefallen : "Fallen tree" [] +@PointClass base(object) size(-18 -18 -16, 18 18 16) = obj_treestump : "Short tree stump" [] +@PointClass base(object) size(-8 -8 -27, 8 8 30) = obj_urn : "Urn (Andorian)" [] +@PointClass base(object) size(-20 -20 -24, 20 20 24) = obj_venusflytrap : "Venus flytrap" [] +@PointClass base(object) size(-3 -20 -55, 3 20 55) = obj_wallringplaque : "Wall ring plaque" [] +@PointClass base(object) size(-2 -18 -20, 2 18 20) = obj_web : "Cobweb" [] +@PointClass base(object) size(-37 -20 -21, 37 20 21) = obj_wheelbarrow : "Wheebarrow" [] +@PointClass base(object) size(-38 -26 -20, 38 26 20) = obj_wheelbarrowdamaged : "Wheebarrow on side" [] +@PointClass base(object) size(-12 -20 -7, 12 20 7) = obj_woodpile : "Wood Pile" [] + +@PointClass base(Targetname) = script_runner : "Script Runner" +[ + script(string) : "Script filename (including subfolder, not including extension)" +] + +@BaseClass base(Appearflags) color(76 76 255) size(-8 -8 -8, 8 8 8) = Sound +[ + spawnflags(Flags) = + [ + 1 : "Not local" : 0 + 2 : "Start off" : 0 + ] + style(integer) : "Style" + attenuation(choices) : "Attenuation" : 0 = + [ + 0 : "No attenuation" + 1 : "Normal" + 2 : "High" + 3 : "Max" + ] + volume(float) : "Volume" : "0.5" + wait(integer) : "Wait" : 10 +] + +@PointClass base(Sound) = sound_ambient_andoria : "Andoria" +[ + style(choices) : "Sound type" : 0 = + [ + 0 : "Nothing" + 1 : "Small fountain" + 2 : "Large fountain" + 3 : "Water running out of sewer" + 4 : "Rushing waterway outside" + 5 : "Wind chime" + ] +] +@PointClass base(Sound) = sound_ambient_cloudfortress : "Cloud Fortress" +[ + style(choices) : "Sound type" : 0 = + [ + 0 : "Nothing" + 1 : "Cauldron bubbling (looping)" + 2 : "Wind, low, eerie (looping)" + 3 : "Wind, low, noisy (looping)" + 4 : "Wind, high, soft (looping)" + 5 : "Wind, low, soft (looping)" + 6 : "Wind, low, strong (looping)" + 7 : "Wind, high, strong (looping)" + 8 : "Wind, whistling, strong (looping)" + ] +] +@PointClass base(Sound) = sound_ambient_hive : "Hive" +[ + style(choices) : "Sound type" : 0 = + [ + 0 : "Nothing" + 1 : "Gong" + 2 : "Wind, low, eerie (looping)" + 3 : "Wind, low, noisy (looping)" + 4 : "Wind, high, soft (looping)" + 5 : "Wind, low, soft (looping)" + 6 : "Wind, low, strong (looping)" + 7 : "Wind, high, strong (looping)" + 8 : "Wind, whistling, strong (looping)" + ] +] +@PointClass base(Sound) = sound_ambient_mine : "Mine" +[ + style(choices) : "Sound type" : 0 = + [ + 0 : "Nothing" + 1 : "Mud pool bubbling (looping)" + 2 : "Rocks falling (3 sounds)" + 3 : "Wind, low, eerie (looping)" + 4 : "Wind, low, soft (looping)" + 5 : "Conveyor belt (looping)" + 6 : "Bucket conveyor belt (looping)" + 7 : "Heavy creaks" + ] +] +@PointClass base(Sound) = sound_ambient_silverspring : "Silverspring" +[ + style(choices) : "Sound type" : 0 = + [ + 0 : "Nothing" + 1 : "Fire (looping)" + 2 : "Water lapping (looping)" + 3 : "Seagulls" + 4 : "Ocean" + 5 : "Birds" + 6 : "Crickets" + 7 : "Frogs" + 8 : "Distant women/children crying" + 9 : "Mosquitoes" + 10 : "Bubbles" + 11 : "Bell" + 12 : "Footsteps" + 13 : "Moans/screams/coughing" + 14 : "Sewer drips" + 15 : "Water drips" + 16 : "Solid drips" + 17 : "Cauldron bubbling" + 18 : "Creaking for the spit that's holding the elf over a fire" + ] +] +@PointClass base(Sound) = sound_ambient_swampcanyon : "Swamp Canyon" +[ + style(choices) : "Sound type" : 0 = + [ + 0 : "Nothing" + 1 : "Bird 1" + 2 : "Bird 2" + 3 : "Huge waterfall" + 4 : "Mud pool bubbling (looping)" + 5 : "Wind, low, eerie (looping)" + 6 : "Wind, low, noisy (looping)" + 7 : "Wind, high, soft (looping)" + 8 : "Wind, low, soft (looping)" + 9 : "Wind, low, strong (looping)" + 10 : "Wind, high, strong (looping)" + 11 : "Wind, whistling, strong (looping)" + ] +] + +@SolidClass base(Appearflags, Targetname) = flamethrower : "Flamethrower. Triggers flame from origin brush when player touches trigger brush, or when triggered if targetted. Sets player on fire if they touch trigger brush, regardless of if the visual flame FX touches them." +[ + spawnflags(Flags) = + [ + 1 : "Steam" + 2 : "Monsters can activate" + ] + angles(string) : "Angles (pitch yaw 0)" + dmg(integer) : "Damage per 1/10th second" : 2 + speed(integer) : "Length" : 400 + wait(choices) : "Wait" : 2 = + [ + -1: "Toggle" + ] +] diff --git a/tools/trenchbroom/games/Hexen2/GameConfig.cfg b/tools/trenchbroom/games/Hexen2/GameConfig.cfg new file mode 100644 index 0000000..d154280 --- /dev/null +++ b/tools/trenchbroom/games/Hexen2/GameConfig.cfg @@ -0,0 +1,23 @@ +{ + "version": 9, + "name": "Hexen 2", + "icon": "Icon.png", + "fileformats": [ + { "format": "Hexen2" }, + { "format": "Valve" } + ], + "filesystem": { + "searchpath": "data1", + "packageformat": { "extension": ".pak", "format": "idpak" } + }, + "materials": { + "root": "textures", + "extensions": [".D"], + "palette": "gfx/palette.lmp", + "attribute": "wad" + }, + "entities": { + "definitions": [ "Hexen2.fgd" ], + "defaultcolor": "0.6 0.6 0.6 1.0" + } +} diff --git a/tools/trenchbroom/games/Hexen2/Hexen2.fgd b/tools/trenchbroom/games/Hexen2/Hexen2.fgd new file mode 100644 index 0000000..3747233 --- /dev/null +++ b/tools/trenchbroom/games/Hexen2/Hexen2.fgd @@ -0,0 +1,1907 @@ + +// +// Hexen 2 game definition file (.fgd) +// For Worldcraft 1.6 and above +// Updated March 17 1998 (By autolycus) +// Updated May 17 2012 (By Amran. Fixed errors, added/corrected entities, and revised original) +// +// Written by autolycus / autolycus@planetquake.com +// Revised by Amran +// + +// +// worldspawn! +// + +@SolidClass = worldspawn : "World entity" +[ + message(string) : "Level name" + worldtype(choices) : "World Type" : 0 = + [ + 0 : "Castle" + 1 : "Egypt" + 2 : "Meso" + 3 : "Roman" + ] + CD(integer) : "CD track to play" : 1 + MIDI(string) : "Midi file to play" : "casa1" + spawnflags2(choices) : "Func_Train type" : 0 = //Spawnflags don't show for worldspawn. Needs to be edited in the .map manually + [ + 0 : "Hexen2 Func_Trains" + 1 : "PoP Func_Trains" + ] + netname(string) : "Netname (PoP)" +] + +// +// Base definitions! +// + +@baseclass = Lights [ + spawnflags(Flags) = + [ + 1 : "Start low" : 0 + 2 : "Hurt (PoP)" : 0 + ] + style(choices) : "Style (32-63 for groups)" : 0 = + [ + 0 : "Normal" + 1 : "Soft flicker" + 6 : "Faster flicker" + + 4 : "Low falloff" + + 5 : "Pulse" + 2 : "Slow pulse in & out" + 11 : "Quick pulse in & out" + + 3 : "Erratic pulse & flicker A" + 7 : "Erratic pulse & flicker B" + 8 : "Erratic pulse & flicker C" + 9 : "Slow blink" + 10 : "Fluorescent flicker" + ] + light(integer) : "Brightness" : 300 + health(integer) : "Health (shootable)" + lightvalue1(integer) : "Lowest light value" : 0 + lightvalue2(integer) : "Highest light value" : 11 + fadespeed(integer) : "Fade speed" : 1 +] + +@baseclass = Appearflags [ + spawnflags(Flags) = + [ + 256 : "Not for Paladin" : 0 + 512 : "Not for Crusader" : 0 + 1024 : "Not for Necromancer" : 0 + 2048 : "Not for Assassin" : 0 + 4096 : "Not in Easy" : 0 + 8192 : "Not in Normal" : 0 + 16384 : "Not in Hard" : 0 + 32768 : "Not in Deathmatch" : 0 + ] +] + +@baseclass = Targetname [ targetname(target_source) : "Name" ] +@baseclass = Target [ target(target_destination) : "Target" ] + +@baseclass = Angles [ + //angles_x(integer) : "Angles X" + //angles_Y(integer) : "Angles Y" + //angles_Z(integer) : "Angles Z" + angles(string) : "Angles (X Y Z)" : "0 0 0" +] + +@baseclass = Spawn [ + bluemana(integer) : "Blue mana" + greenmana(integer) : "Green mana" + cnt_torch(integer) : "Torch" + cnt_h_boost(integer) : "Quartz flask" + cnt_sh_boost(integer) : "Mystic urn" + cnt_mana_boost(integer) : "Krater of might" + cnt_teleport(integer) : "Chaos device" + cnt_tome(integer) : "Tome of power" + cnt_summon(integer) : "Stone of summoning" + cnt_invisibility(integer) : "Invisibility" + cnt_glyph(integer) : "Glyph of ancients" + cnt_haste(integer) : "Boots of speed" + cnt_blast(integer) : "Disc of repulsion" + cnt_polymorph(integer) : "Ovinimancer" + cnt_cubeofforce(integer) : "Force cube" + cnt_invincibility(integer) : "Invincibility" +] + +// +// Entities! +// + +@PointClass base(Appearflags, Targetname) size(-8 -8 -8, 8 8 8) = air_bubbles : "Air bubbles (PoP)" [ + cnt(integer) : "Number of Bubbles" : 1 + wait(integer) : "Wait Style (-2 for burst)" : 0 +] + +// +// Artifacts! +// + +@BaseClass base(Appearflags, Targetname, Target) size(-8 -8 -44, 8 8 20) = Artifact +[ + spawnflags(Flags) = + [ + 1 : "Floating" : 0 + ] + message(string) : "Message" + style(integer) : "Light Style" +] +@PointClass base(Artifact) model({ "path": ":models/a_blast.mdl" }) = art_blastradius : "Blast Radius" [] +@PointClass base(Artifact) model({ "path": ":models/a_cube.mdl" }) = art_cubeofforce : "Cube of Force" [] +@PointClass base(Artifact) model({ "path": ":models/a_glyph.mdl" }) = art_glyph : "Glyph" [] +@PointClass base(Artifact) model({ "path": ":models/a_haste.mdl" }) = art_haste : "Haste" [] +@PointClass base(Artifact) model({ "path": ":models/a_hboost.mdl" }) = art_HealthBoost : "Health Boost" [] +@PointClass base(Artifact) model({ "path": ":models/a_invinc.mdl" }) = art_invincibility : "Invincibility" [] +@PointClass base(Artifact) model({ "path": ":models/a_invis.mdl" }) = art_invisibility : "Invisibility" [] +@PointClass base(Artifact) model({ "path": ":models/a_mboost.mdl" }) = art_manaboost : "Mana Boost" [] +@PointClass base(Artifact) model({ "path": ":models/a_poly.mdl" }) = art_polymorph : "Polymorph" [] +@PointClass base(Artifact) model({ "path": ":models/a_summon.mdl" }) = art_summon : "Summoning" [] +@PointClass base(Artifact) model({ "path": ":models/a_shbost.mdl" }) = art_SuperHBoost : "Super Health Boost" [] +@PointClass base(Artifact) model(":models/xcalibur.mdl") = art_sword_and_crown : "Sword and Crown" [] +@PointClass base(Artifact) model({ "path": ":models/a_telprt.mdl" }) = art_teleport : "Teleport" [] +@PointClass base(Artifact) model({ "path": ":models/a_tome.mdl" }) = art_tomeofpower : "Tome of Power" [] +@PointClass base(Artifact) model({ "path": ":models/a_torch.mdl" }) = art_torch : "Torch" [] + +// +// Entities! +// + +@PointClass base(Appearflags, Targetname) = buddha_trigger_endgame : "Buddha trigger endgame (PoP)" [] + +@SolidClass base(Appearflags, Targetname, Target) = breakable_brush : "Breakable brush" +[ + spawnflags(Flags) = + [ + 1 : "Kill All" : 0 + 2 : "Hierarchy" : 0 + 4 : "No Link" : 0 + 8 : "Check Name" : 0 + 16 : "Ordered" : 0 + 32 : "Translucent" : 0 + 64 : "Invincible" : 0 + 128 : "Invisible" : 0 + ] + killtarget(target_destination) : "KillTarget" + flags(integer) : "Hierachial order" + thingtype(choices) : "Material type" : 0 = + [ + 0 : "Glass" + 1 : "Grey stone" + 2 : "Wood" + 3 : "Metal" + 4 : "Flesh" + 5 : "Fire" + 6 : "Clay" + 7 : "Leaves" + 8 : "Hay" + 9 : "Brown stone" + 10 : "Cloth" + 11 : "Wood & leaf" + 12 : "Wood & metal" + 13 : "Wood & stone" + 14 : "Metal & stone" + 15 : "Metal & cloth" + 16 : "Spider web" + //17 : "Glass" + 18 : "Ice" + 19 : "Clear glass" + 20 : "Red glass" + ] + health(choices) : "Health" : 0 = + [ + 0 : "Based on material" + ] + abslight(integer) : "Absolute light level" +] + +@SolidClass base(Appearflags, Targetname) = brush_pushable : "Pushable brush" +[ + mass(integer) : "Mass" : 5 + thingtype(choices) : "Material type" : 1 = + [ + 0 : "No sound" + 1 : "Stone/ceramic" + 2 : "Wood" + //4 : "Metal" //Listed on Eye of Horus, doesn't work though? + ] +] + +@PointClass base(Appearflags, Targetname) size(-8 -8 -8, 8 8 8) = camera_remote : "Camera" +[ + target(target_destination) : "Target (target_null)" + wait(integer) : "Time in camera mode" : 3 + angles_x(integer) : "Pitch (optional)" + angles_y(integer) : "Yaw (optional)" + netname(string) : "Netname (PoP)" +] + +// +// Func Entities! +// + +@SolidClass base(Appearflags, Targetname, Target) = func_angletrigger : "Angle trigger" +[ + spawnflags(Flags) = + [ + 1 : "Reverse" : 0 + 2 : "X axis" : 0 + 4 : "Y axis" : 0 + ] + mangle(string) : "Mangle (x y z)" + cnt(integer) : "Degrees per move" + speed(integer) : "Speed" : 40 + dmg(integer) : "Damage when blocked" + netname(string) : "Netname" + abslight(integer) : "Absolute light level" +] + +@BaseClass base(Appearflags, Targetname, Target) = Button [ + spawnflags(Flags) = + [ + 1 : "Deactivated" : 0 + 2 : "Fired only" : 0 + 4 : "Fire multiple" : 0 + ] + speed(integer) : "Speed" : 40 + wait(choices) : "Wait" : 1 = + [ + -1 : "Stay pressed" + ] + message(string) : "Message" + delay(integer) : "Delay" + lip(integer) : "Lip" : 4 + health(integer) : "Health" + soundtype(choices) : "Sounds" : 0 = + [ + 0 : "Steam metal" + 1 : "Wooden clunk" + 2 : "Metallic click" + 3 : "In-out" + ] + netname(string) : "Netname" + abslight(integer) : "Absolute light value" +] + +@SolidClass base(Button) = func_button : "Button" +[ + msg2(string) : "Deactivated Message" + aflag(integer) : "Order" +] + +@SolidClass base(Appearflags, Targetname) = func_crusher : "Crusher" +[ + spawnflags(Flags) = + [ + 1 : "Multiple" : 0 + 2 : "Slide" : 0 + 4 : "Start open" : 0 + 8 : "End open" : 0 + ] + speed(integer) : "Speed" : 150 + dmg(integer) : "Damage" : 10 + lip(integer) : "Lip" : 4 + wait(integer) : "Wait" : 1 + soundtype(choices) : "Sounds" : 1 = + [ + 1 : "Base fast" + 2 : "Chain slow" + 3 : "Guillotine" + ] +] + +@BaseClass base(Appearflags, Targetname, Target) = Door +[ + spawnflags(Flags) = + [ + 1 : "Start open" : 0 + 2 : "Reverse" : 0 + 4 : "Don't link" : 0 + ] + message(string) : "Message" + health(integer) : "Health (shootable)" + speed(integer) : "Speed" : 100 + wait(choices) : "Wait" : 3 = + [ + 3 : "Default (3)" + -1 : "Never return" + ] + dmg(choices) : "Damage" : 2 = + [ + 2 : "Default (2)" + 666 : "Instant kill (666)" + ] + strength(integer) : "Strength" : 1 //What is this key for? + soundtype(choices) : "Sounds" : 2 = + [ + 0 : "No sound" + 1 : "Big metal door, swinging" + 2 : "Big stone door, sliding" + 3 : "Big wood door, swinging" + 4 : "Normal wood door, swinging" + 5 : "Big wood door, sliding" + 6 : "Drawbridge" + 7 : "Rotating walkway" + 8 : "Big metal door, sliding" + 9 : "Pendulum swinging" + ] +] + +@SolidClass base(Door) = func_door : "Door" +[ + spawnflags(Flags) = + [ + 8 : "Toggle" : 0 + 16 : "Slide" : 0 + 32 : "Normal move" : 0 + 64 : "Remove puzzle" : 0 + 128 : "No puzzle" : 0 + ] + level(integer) : "Movement length" + lip(integer) : "Lip" : 8 + //v_angle(string) : "Angle to turn" : "0 0 0" //What is this key for? + //anglespeed(integer) : "Turning speed" : 0 //What is this key for? + puzzle_piece_1(integer) : "Puzzle Piece 1" + puzzle_piece_2(integer) : "Puzzle Piece 2" + puzzle_piece_3(integer) : "Puzzle Piece 3" + puzzle_piece_4(integer) : "Puzzle Piece 4" + no_puzzle_msg(string) : "Puzzle message" + close_target(string) : "Close Target (PoP)" + abslight(integer) : "Absolute light value" +] + +@SolidClass base(Door) = func_door_rotating : "Rotating door" +[ + spawnflags(Flags) = + [ + 8 : "Remove puzzle" : 0 + 16 : "No puzzle" : 0 + 32 : "Toggle" : 0 + 64 : "X axis" : 0 + 128 : "Y axis" : 0 + ] + flags(integer) : "Degrees of rotation" + flags2(integer) : "Damage when touched" + puzzle_piece_1(integer) : "Puzzle Piece 1" + puzzle_piece_2(integer) : "Puzzle Piece 2" + puzzle_piece_3(integer) : "Puzzle Piece 3" + puzzle_piece_4(integer) : "Puzzle Piece 4" + no_puzzle_msg(string) : "Puzzle message" + close_target(string) : "Close Target (PoP)" + abslight(integer) : "Absolute light value" +] + +@SolidClass base(Door) = func_door_secret : "Secret door" +[ + spawnflags(Flags) = + [ + 1 : "Open once" : 0 + 2 : "Move left first" : 0 + 4 : "Move down first" : 0 + 8 : "No shoot" : 0 + 16 : "Always shoot" : 0 + 32 : "" : 0 + 64 : "Remove puzzle" : 0 + 128: "No puzzle" : 0 + ] + t_width(integer) : "Override width" + t_length(integer) : "Override length" +] + +@SolidClass base(Appearflags) = func_illusionary : "Illusionary brush" +[ + spawnflags(Flags) = + [ + 1 : "Translucent" : 0 + 2 : "Light" : 0 + ] + abslight(integer) : "Absolute light value" +] + +@PointClass base(Appearflags, Targetname) size(-16 -16 0, 16 16 56) = func_monsterspawner : "spawner" +[ + spawnflags(Flags) = + [ + 1 : "Imp" : 0 + 2 : "Archer" : 0 + 4 : "Wizard" : 0 + 8 : "Scorpian" : 0 + 16 : "Spider" : 0 + 32 : "On death" : 0 + 64 : "Quiet" : 0 + 128 : "Trigger only" : 0 + ] + cnt(integer) : "Number of spawns" : 17 + spawnername(string) : "Spawner name" + wait(integer) : "Time between spawns (0.5)" : 0 +] + +@PointClass base(Appearflags, Targetname) size(-16 -16 0, 16 16 56) = func_monsterspawner_mp : "spawner (PoP)" +[ + spawnflags(Flags) = + [ + 1 : "Ice archer" : 0 + 2 : "Ice imp" : 0 + 4 : "Snow leopard" : 0 + 8 : "Weretiger" : 0 + 16 : "Yakman" : 0 + 32 : "On death" : 0 + 64 : "Quiet" : 0 + 128 : "Trigger only" : 0 + ] + cnt(integer) : "Number of spawns" : 17 + spawnername(string) : "Spawner name" + wait(integer) : "Time between spawns (0.5)" : 0 +] + +@PointClass base(Appearflags, Targetname) size(-16 -16 0, 16 16 56) = func_monsterspawn_spot : "spawn spot" +[ + spawnflags(Flags) = + [ + 1 : "Imp" : 0 + 2 : "Archer" : 0 + 4 : "Wizard" : 0 + 8 : "Scorpian" : 0 + 16 : "Spider" : 0 + 32 : "On death" : 0 + 64 : "Quiet" : 0 + 128 : "Trigger only" : 0 + ] + //cnt(integer) : "Number of spawns" : 17 //cnt should be filled out on monsterspawner, not the spot. (Crashes if it reaches the limit) + spawnername(string) : "Spawner name" + wait(integer) : "Time between spawns (0.5)" : 0 + aflag(integer) : "Spawn order" + dflags(choices) : "Wait when failed" : 0 = //"If dflags is set to "1", the spawner will wait it's "wait" value every time it fails to spawn a monster." + [ + 0 : "No" + 1 : "Yes" + ] +] + +@PointClass base(Appearflags, Targetname) size(-16 -16 0, 16 16 56) = func_monsterspawn_spot_mp : "spawn spot (PoP)" +[ + spawnflags(Flags) = + [ + 1 : "Ice archer" : 0 + 2 : "Ice imp" : 0 + 4 : "Snow leopard" : 0 + 8 : "Weretiger" : 0 + 16 : "Yakman" : 0 + 32 : "On death" : 0 + 64 : "Quiet" : 0 + 128 : "Trigger only" : 0 + ] + //cnt(integer) : "Number of spawns" : 17 //cnt should be filled out on monsterspawner, not the spot. (Crashes if it reaches the limit) + spawnername(string) : "Spawner name" + wait(integer) : "Time between spawns (0.5)" : 0 + aflag(integer) : "Spawn order" + dflags(choices) : "Wait when failed" : 0 = //"If dflags is set to "1", the spawner will wait it's "wait" value every time it fails to spawn a monster." + [ + 0 : "No" + 1 : "Yes" + ] +] + +@SolidClass base(Appearflags, Targetname) = func_newplat : "New plat" +[ + spawnflags(Flags) = + [ + 1 : "Bottom start" : 0 + 2 : "Return to start" : 0 + 4 : "Continuous" : 0 + ] + speed(integer) : "Speed" : 150 + height(integer) : "Height" + soundtype(choices) : "Sounds" : 1 = + [ + 1 : "Pully" + 2 : "Chain" + ] + dmg(integer) : "Damage" : 0 + wait(integer) : "Wait" : 3 +] + +@SolidClass base(Appearflags, Targetname) = func_plat : "Plat" +[ + spawnflags(Flags) = + [ + 1 : "Trigger low" : 0 + ] + speed(integer) : "Speed" : 150 + height(integer) : "Height" + soundtype(choices) : "Sounds" : 1 = + [ + 1 : "Pully" + 2 : "Chain" + ] + dmg(integer) : "Damage" : 0 + wait(integer) : "Wait" : 3 +] + +@SolidClass base(Button) = func_pressure : "Pressure plate" +[ + spawnflags(Flags) = + [ + 1 : "Activate" : 0 + 2 : "" : 0 + 4 : "" : 0 + ] + mass(integer) : "Mass required" +] + +@SolidClass base(Appearflags, Targetname) = func_rotating : "Rotating object" +[ + spawnflags(Flags) = + [ + 1 : "Start on" : 0 + 2 : "Reverse" : 0 + 4 : "X axis" : 0 + 8 : "Y axis" : 0 + 16 : "Breakable" : 0 + 32 : "Gradual" : 0 + 64 : "Toggle reverse" : 0 + 128 : "Keep start" : 0 + ] + speed(integer) : "Speed" : 100 + dmg(integer) : "Damage when blocked" : 2 + lifetime(choices) : "Lifetime" : 0 = + [ + 0 : "Continuous" + ] + wait(integer) : "Time between lifetimes" : 3 + thingtype(choices) : "Material type" : 2 = + [ + 0 : "Glass" + 1 : "Grey stone" + 2 : "Wood" + 3 : "Metal" + 4 : "Flesh" + 5 : "Fire" + 6 : "Clay" + 7 : "Leaves" + 8 : "Hay" + 9 : "Brown stone" + 10 : "Cloth" + 11 : "Wood & leaf" + 12 : "Wood & metal" + 13 : "Wood & stone" + 14 : "Metal & stone" + 15 : "Metal & cloth" + 16 : "Spider web" + //17 : "Glass" + 18 : "Ice" + 19 : "Clear glass" + 20 : "Red glass" + ] + health(choices) : "Health" : 0 = + [ + 0 : "Based on material" + ] + anglespeed(integer) : "Accel/decell time" : 10 + abslight(integer) : "Absolute light value" +] + +@SolidClass base(Appearflags, Targetname) = func_rotating_movechain : "Move chain" //Is supposed to link rotating ents to moving ents. Untested +[ + spawnflags(Flags) = + [ + 1 : "No angle chain" : 0 + ] + dmg(integer) : "Damage on touch" + noise(string) : "Noise" + noise1(string) : "Impact noise" + wait(integer) : "Length of sound (for looping)" + avelocity(string) : "Pitch/Yaw/Roll" : "0 0 0" + netname(string) : "Netname" + abslight(integer) : "Absolute light value" +] + +@SolidClass base(Appearflags, Targetname, Target) = func_train : "Train" +[ + spawnflags(Flags) = + [ + 1 : "Glow" : 0 + 2 : "Toggle" : 0 + 4 : "Return" : 0 + 8 : "Translucent" : 0 + ] + speed(integer) : "Speed" : 100 + dmg(integer) : "Damage when blocked" : 2 + soundtype(choices) : "Sound" : 1 = + [ + 0 : "No sound" + 1 : "Ratchet metal" + ] + anglespeed(integer) : "Speed of rotation" : 100 + wait(choices) : "Wait between moves" : 0 = + [ + 0 : "No wait" + -1 : "Stop" + -2 : "Explode" + ] + pausetime(integer) : "Pause before explode" + thingtype(choices) : "Material" : 1 = + [ + 0 : "Glass" + 1 : "Grey stone" + 2 : "Wood" + 3 : "Metal" + 4 : "Flesh" + 5 : "Fire" + 6 : "Clay" + 7 : "Leaves" + 8 : "Hay" + 9 : "Brown stone" + 10 : "Cloth" + 11 : "Wood & leaf" + 12 : "Wood & metal" + 13 : "Wood & stone" + 14 : "Metal & stone" + 15 : "Metal & cloth" + 16 : "Spider web" + //17 : "Glass" + 18 : "Ice" + 19 : "Clear glass" + 20 : "Red glass" + ] + abslight(integer) : "Absolute light value" +] + +@SolidClass base(Appearflags, Targetname, Target) = func_train_mp : "Train (PoP)" +[ + spawnflags(Flags) = + [ + 1 : "Invisible" : 0 + 2 : "Toggle" : 0 + 4 : "Return" : 0 + 8 : "Translucent" : 0 + 16 : "Slope" : 0 + 32 : "Angle match" : 0 + 64 : "Use origin" : 0 + 128 : "Angle wait" : 0 + ] + speed(integer) : "Speed" : 100 + dmg(integer) : "Damage when blocked" : 2 + soundtype(choices) : "Sound" : 1 = + [ + 0 : "No sound" + 1 : "Ratchet metal" + 2 : "Pullies" + 3 : "Sliding" + 4 : "Machine" + 5 : "Gears" + 6 : "Guillotine" + 7 : "Chain" + 8 : "Rolling boulder" + 9 : "Prayer wheel" + ] + level(choices) : "Sound falloff" : 0 = + [ + 0 : "Normal" + 1 : "No falloff" + ] + weaponmodel(string) : "Model path" + angles(string) : "Angles (x y z)" + health(integer) : "Health" + anglespeed(integer) : "Speed of rotation" : 100 + wait(choices) : "Wait between moves" : 0 = + [ + 0 : "No wait" + -1 : "Stop" + -2 : "Explode" + -3 : "Wait at next corner" + ] + pausetime(integer) : "Pause before explode" + thingtype(choices) : "Material" : 1 = + [ + 0 : "Glass" + 1 : "Grey stone" + 2 : "Wood" + 3 : "Metal" + 4 : "Flesh" + 5 : "Fire" + 6 : "Clay" + 7 : "Leaves" + 8 : "Hay" + 9 : "Brown stone" + 10 : "Cloth" + 11 : "Wood & leaf" + 12 : "Wood & metal" + 13 : "Wood & stone" + 14 : "Metal & stone" + 15 : "Metal & cloth" + 16 : "Spider web" + //17 : "Glass" + 18 : "Ice" + 19 : "Clear glass" + 20 : "Red glass" + ] + abslight(integer) : "Absolute light value" +] + +@SolidClass base(Appearflags, Targetname) = func_wall : "Wall" +[ + spawnflags(Flags) = + [ + 1 : "Translucent" : 0 + ] + abslight(integer) : "Absolute light value" +] + +// +// FX Entities! +// + +@PointClass base(Appearflags, Targetname) size(-8 -8 -8, 8 8 8) = fx_colorbeam_end : "End of beam" [] +@PointClass base(Appearflags, Targetname, Target) size(-8 -8 -8, 8 8 8) = fx_colorbeam_start : "Start of beam" +[ + spawnflags(Flags) = + [ + 1 : "start off" : 0 + ] + noise(choices) : "Noise" : 1 = + [ + 1 : "No sound (default)" + 2 : "Lightning" + ] + wait(choices) : "Wait" : -1 = + [ + -1 : "Triggerable" + ] + color(choices) : "Color" : 0 = + [ + 0 : "Red" + 1 : "Blue" + 2 : "Green" + 3 : "White" + 4 : "Yellow" + ] + lifespan(integer) : "Lifespan" +] + +@SolidClass base(Appearflags, Targetname) = fx_friction_change : "Friction change (PoP)" +[ + friction(choices) : "Friction" : 1 = + [ + 1 : "Normal (1)" + 0 : "Slippery (> 0, < 1)" + 2 : "High (> 1)" + ] +] + +@PointClass base(Appearflags, Targetname) size(-8 -8 -8, 8 8 8) = fx_smoke_generator : "smoker" +[ + wait(integer) : "Time between puffs" : 2 + thingtype(choices) : "Type of smoke" : 0 = + [ + 0 : "White puff" + 1 : "Red" + 2 : "Green" + 3 : "Grey" + ] + lifespan(integer) : "Lifespan override" +] + +// +// Info Entities! +// + +@PointClass base(Appearflags) size(-16 -16 -16, 16 16 16) = info_intermission : "intermission camera" +[ + mangle(string) : "Pitch/Roll/Yaw" : "0 0 0" +] + +@PointClass base(Appearflags, Targetname) size(-4 -4 -4, 4 4 4) = info_null : "null target" +[ + spawnflags(Flags) = + [ + 1 : "Don't remove" : 0 + ] +] + +@baseclass base(Appearflags, Targetname) size(-16 -16 -32, 16 16 32) color(0 255 0) = PlayerClass [] + +@PointClass base(PlayerClass) = info_player_start : "Player 1 start" [] +@PointClass base(PlayerClass) = info_player_start2 : "Player 1 start (PoP)" [] +@PointClass base(PlayerClass) = info_player_coop : "Player cooperative start" +[ + target(target_destination) : "Target (PoP)" + map(string) : "Map (PoP)" + playerclass(integer) : "Player class (PoP)" +] +@PointClass base(PlayerClass) = info_player_deathmatch : "Player deathmatch start" [] +@PointClass base(PlayerClass) = info_teleport_destination : "Teleport destination" +[ + spawnflags(Flags) = + [ + 1 : "No throw" : 0 + ] +] + +// +// Items! +// + +@BaseClass base(Appearflags, Targetname, Target) size(-8 -8 -20, 8 8 45) = Item +[ + spawnflags(Flags) = + [ + 1 : "floating" : 0 + ] + message(string) : "Message" + style(integer) : "Light Style" +] + +@PointClass base(Item) = item_armor_amulet : "Armor amulet" [] +@PointClass base(Item) = item_armor_bracer : "Armor bracer" [] +@PointClass base(Item) = item_armor_breastplate : "Breastplate" [] +@PointClass base(Item) = item_armor_helmet : "Helmet" [] +@PointClass base(Item) = item_health : "10 health" [] +@PointClass base(Item) = item_mana_both : "Mana" +[ + spawnflags(Flags) = + [ + 2 : "big (30)" : 0 + ] +] +@PointClass base(item_mana_both) = item_mana_blue : "blue mana" [] +@PointClass base(item_mana_both) = item_mana_green : "green mana" [] + +@PointClass base(Appearflags, Targetname, Spawn) size(-8 -8 -20, 8 8 45) = item_spawner : "Item spawner" +[ +] + +// +// Lights! +// + +@PointClass base(Appearflags, Targetname, Target, Lights) size(-8 -8 -8, 8 8 8) = light : "normal light" [] + +@baseclass = Lightdmg +[ + dmg(integer) : "Damage (PoP)" +] + +@PointClass base(light, Lightdmg) model(":models/flame1.mdl") size(-10 -10 -40, 10 10 40) = light_flame_large_yellow : "Flame large yellow"[] +@PointClass base(light) model(":models/flame2.mdl") size(-10 -10 -12, 12 12 18) = light_flame_small_white : "Flame small white"[] +@PointClass base(light, Lightdmg) model(":models/flame2.mdl") size(-10 -10 -12, 12 12 18) = light_flame_small_yellow : "Flame small yellow"[] +@PointClass base(light, Angles) size(-8 -8 -8, 8 8 8) = light_gem : "Gem light" [] +@PointClass base(light) size(-8 -8 -8, 8 8 8) = light_globe : "Globe" [] +@PointClass base(light) model(":models/cflmtrch.mdl") size(-8 -8 -8, 8 8 8) = light_torch_castle : "Castle torch" [] +@PointClass base(light_torch_castle) model(":models/egtorch.mdl") = light_torch_egypt : "Egyptian torch" [] +@PointClass base(light_torch_castle) model(":models/mflmtrch.mdl") = light_torch_meso : "Meso torch" [] +@PointClass base(light_torch_castle) model(":models/rflmtrch.mdl") = light_torch_rome : "Roman torch" [] +@PointClass base(light, Lightdmg) model(":models/flame.mdl") size(-10 -10 -20, 10 10 20) = light_torch_small_walltorch : "Walltorch" +[ + light(integer) : "Brightness" : 200 +] + +@PointClass base(light, Lightdmg) size(-16 -16 -52, 16 16 16) = light_burner : "Burner (PoP)" [] +@PointClass base(light) size(-8 -8 -16, 8 8 32) = light_candle : "Candle (PoP)" [] +@PointClass base(light) size(-8 -8 -40, 8 8 8) = light_lantern : "Lantern (PoP)" [] +@PointClass base(light, Lightdmg) size(-48 -48 -4, 48 48 224) = light_newfire : "Newfire (PoP)" [] +@PointClass base(light, Lightdmg) size(-0 -16 -0, 22 16 32) = light_palace_torch : "Palace torch (PoP)" [] + +@PointClass base(Appearflags, Targetname) size(-8 -8 -8, 8 8 8) = light_thunderstorm : "Thunderstorm" +[ + light(integer) : "Brightness" : 300 + wait(integer) : "Wait (1 - 100)" : 33 + dmg(integer) : "Lightning frequency" : 10 + lightvalue1(integer) : "Normal light value" : 11 + frags(integer) : "Lightning area radius" : 1000 + style(integer) : "Light Style" +] + +// +// Misc Entities! +// + +@PointClass base(Appearflags, Targetname) size(-8 -8 -8, 8 8 8) = misc_fireball : "Lava balls" [] + +@PointClass base(Appearflags, Targetname) size(0 0 0, 32 32 32) = misc_fountain : "Fountain" +[ + angles(string) : "Angles (x y z)" : "0 0 0" + movedir(string) : "Direction (x y z)" : "1 1 1" + color(integer) : "Color" : 407 + cnt(integer) : "Number of particles" : 2 +] + +// +// Monsters! +// + +@BaseClass base(Appearflags, Targetname, Target, Spawn) size(-16 -16 0, 16 16 50) = Monster +[ + spawnflags(Flags) = + [ + 1 : "Ambush" : 0 //Only wakes up when player is within this enemies line of sight + 2 : "Stuck" : 0 //Cannot move from original position (only some enemies) + 4 : "Jump" : 0 //Has the ability to leap forward; automatically set on some enemies (such as spiders) + 8 : "Play dead (PoP)" : 0 //Possibly no useful effect? + 16 : "Dormant" : 0 //Possibly no useful effect? + 32 : "No drop" : 0 //Doesn't drop to floor on spawn according to HC (may not be implemented) + 64 : "Frozen (PoP)" : 0 //Enemy is made out of ice + ] + health(integer) : "Health (PoP)" + experience(integer) : "Experience (PoP)" //Doesn't seem to work +] + +@PointClass base(Monster) model(":models/archer.mdl") = monster_archer : "Archer" [] +@PointClass base(Monster) model(":models/archer.mdl") = monster_archer_lord : "Archer lord" [] + +@PointClass base(Monster) model(":models/fangel.mdl") size(-14 -14 -41, 14 14 23) = monster_fallen_angel : "Fallen angel" [] +@PointClass base(Monster) model(":models/fangel.mdl") size(-14 -14 -41, 14 14 23) = monster_fallen_angel_lord : "Fallen angel lord" [] + +@PointClass base(Monster) model(":models/golem_s.mdl") size(-32 -32 0, 32 32 112) = monster_golem_stone : "Stone golem" [] +@PointClass base(Monster) model(":models/golem_i.mdl")size(-55 -55 0, 55 55 120) = monster_golem_iron : "Iron golem" [] +@PointClass base(Monster) model(":models/golem_b.mdl") size(-64 -64 0, 64 64 194) = monster_golem_bronze : "Bronze golem" [] +@PointClass base(Monster) model(":models/golem_s.mdl") size(-32 -32 -24, 32 32 64) = monster_golem_crystal : "Crystal golem" [] + +@PointClass base(Monster) model(":models/hydra.mdl") size(-40 -40 -42, 40 40 42) = monster_hydra : "Hydra" +[ + spawnflags(Flags) = + [ + 1 : "Stand" : 0 + 2 : "Hover" : 0 + ] +] + +@PointClass base(Monster) model(":models/imp.mdl") = monster_imp_fire : "Fire imp" +[ + spawnflags(Flags) = + [ + 1 : "Stand" : 0 + 2 : "Hover" : 0 + 4 : "" : 0 + 8 : "" : 0 + 16 : "Gargoyle" : 0 + 32 : "" : 0 + 64 : "" : 0 + ] + wait(integer) : "Wait (-1 for decoration)" +] +@PointClass base(monster_imp_fire) model(":models/imp.mdl") = monster_imp_ice : "Ice imp" [] +@PointClass base(monster_imp_fire) model(":models/imp.mdl") = monster_imp_lord : "Lord imp" [] + +@PointClass base(Monster) model(":models/medusa.mdl") = monster_medusa_green : "Green medusa" [] +@PointClass base(monster_medusa_green) model(":models/medusa2.mdl") = monster_medusa_red : "Red medusa" [] + +@PointClass base(Monster) model(":models/mummy.mdl") size(-16 -16 0, 16 16 55) = monster_mummy : "Mummy" [] +@PointClass base(monster_mummy) model(":models/mummy.mdl") = monster_mummy_lord : "Mummy lord" [] + +@PointClass base(Monster) model(":models/scorpion.mdl") size(-40 -40 0, 40 40 64) = monster_scorpion_yellow : "Yellow scorpion" [] +@PointClass base(monster_scorpion_yellow) model(":models/scorpion.mdl") = monster_scorpion_black : "Black scorpion" [] + +@PointClass base(Monster) model(":models/skullwiz.mdl") size(-24 -24 0, 24 24 64) = monster_skull_wizard : "Skull wizard" [] +@PointClass base(monster_skull_wizard) model(":models/skullwiz.mdl") = monster_skull_wizard_lord : "Skull wizard lord" [] + +@BaseClass base(Monster) model(":models/spider.mdl") = Spider +[ + spawnflags(Flags) = + [ + 32 : "On wall" : 0 + ] +] +@PointClass base(Spider) size(-12 -12 0, 12 12 16) = monster_spider_red_small : "Small red spider" [] +@PointClass base(Spider) size(-16 -16 0, 16 16 26) = monster_spider_red_large : "Big red spider" [] +@PointClass base(Spider) size(-12 -12 0, 12 12 16) = monster_spider_yellow_small : "Small yellow spider" [] +@PointClass base(Spider) size(-16 -16 0, 16 16 26) = monster_spider_yellow_large : "Big yellow spider" [] + +@PointClass base(Monster) model(":models/mezzoman.mdl") = monster_werejaguar : "Werejaguar" [] +@PointClass base(monster_werejaguar) model(":models/mezzoman.mdl") = monster_werepanther : "Werepanther" [] + +@PointClass base(Appearflags, Targetname, Target) model(":models/fish.mdl") size(-16 -16 -8, 16 16 8) = monster_fish : "Fish" +[ + skin(choices) : "Skin" : 0 = + [ + 0 : "Bright colored" + 1 : "Darker colored" + ] +] +@PointClass base(Appearflags, Targetname, Target) model(":models/rat.mdl") size(-3 -3 0, 3 3 7) = monster_rat : "Rat" +[ + spawnflags(Flags) = + [ + 1 : "Ambush" : 0 + ] +] +@PointClass base(monster_rat) size(-20 -20 0, 20 20 10) = monster_ratnest : "Rat's nest" [] +@PointClass base(Monster) model(":models/raven.mdl") size(-16 -16 0, 16 16 32) = monster_raven : "Raven" [] + +@PointClass base(Appearflags, Targetname, Target) model(":models/snake.mdl") size(-80 -80 0, 80 80 200) = monster_snake : "Snake" +[ + spawnflags(Flags) = + [ + 1 : "Ambush" : 0 + ] +] +@PointClass base(Appearflags, Targetname, Target) model(":models/eidolon.mdl") size(-100 -100 0, 100 100 666) = monster_eidolon : "Eidolon" [] + +// +// PoP Monsters! +// + +@PointClass base(Monster) model(":models/archer.mdl") = monster_archer_ice : "Ice archer (PoP)" [] +@PointClass base(Monster) size(-20 -20 0, 20 20 40) = monster_pentacles : "Pentacle (PoP)" +[ + skin(choices) : "Skin" : 0 = + [ + 0 : "Rocky brown" + 1 : "Snowy white" + ] +] +@PointClass base(Monster) model(":models/mezzoman.mdl") = monster_weretiger : "Were tiger (PoP)" [] +@PointClass base(Monster) model(":models/mezzoman.mdl") = monster_weresnowleopard : "Were leopard (PoP)" [] +@PointClass base(Monster) size(-32 -32 0, 32 32 104) model(":models/yakman.mdl") = monster_yakman : "Yakman (PoP)" +[ + skin(choices) : "Skin" : 0 = + [ + 0 : "White" // Greater chance to shoot ice + 1 : "Brown" // Even chance + 2 : "Black" // Greater chance to charge + ] +] +@PointClass base(Appearflags, Targetname, Target) size(-100 -100 0, 100 100 666) = monster_eidolon_weakling : "Eidolon weakling (PoP)" [] +@PointClass base(Appearflags, Targetname, Target) model(":models/pravus.mdl") size(-8 -8 -8, 8 8 8) = monster_buddha : "Praevus (PoP)" +[ + netname(string) : "Netname" +] + +// +// Objects! +// + +@PointClass base(Appearflags, Targetname, Target) model(":models/ballista.mdl") size(-45 -45 0, 45 45 60) = obj_ballista : "Ballista" +[ + spawnflags(Flags) = + [ + 1 : "Track" : 0 + ] + health(choices) : "Health" : 0 = + [ + 0 : "Indestructible" + ] + cnt(integer) : "Degrees of pitch off start" : 30 + count(integer) : "Degrees per movement" : 5 + dmg(integer) : "Damage of projectile" : 50 + speed(integer) : "Delay between firings" : 5 + //mass(integer) : "Mass" +] + +@BaseClass base(Appearflags, Targetname, Target, Angles, Spawn) = Object +[ + health(integer) : "Health" + scale(integer) : "Scale" + mass(integer) : "Mass" + message(string) : "Message" + abslight(integer) : "Absolute light value" +] + +@BaseClass base(Object) model(":models/barrel.mdl") size(-13 -13 0, 13 13 36) = Barrels +[ + spawnflags(Flags) = + [ + 1 : "Downhill" : 0 + 2 : "No drop" : 0 + 4 : "On side" : 0 + 8 : "Sink" : 0 + ] +] +@PointClass base(Barrels) = obj_barrel : "Barrel" +[ + health(integer) : "Health" : 25 +] +@PointClass base(Barrels) = obj_barrel_exploding : "Barrel exploding" [] +@PointClass base(Barrels) = obj_barrel_indestructible : "Barrel indestructible" [] + +@PointClass base(Object) model(":models/stool.mdl") size(-10 -10 -5, 10 10 32) = obj_barstool : "Bar stool" [] +@PointClass base(Object) size(-16 -16 0, 16 16 40) = obj_beefslab : "Slab o' beef" [] +@PointClass base(Object) model(":models/bellring.mdl") size(-100 -100 -210, 100 100 8) = obj_bell : "Bell" [] +@PointClass base(Object) model(":models/bench.mdl") size(-30 -30 0, 30 30 40) = obj_bench : "Bench" [] +@PointClass base(Object) model(":models/bonepile.mdl") size(-10 -10 0, 10 10 10) = obj_bonepile : "Pile o' bones" [] +@PointClass base(Object) size(-8 -8 0, 8 8 10) = obj_book_closed : "Closed book" [] +@PointClass base(obj_book_closed) = obj_book_open : "Open book" [] +@PointClass base(Object) model(":models/bush1.mdl") size(-16 -16 0, 16 16 40) = obj_bush1 : "Bush" [] +@PointClass base(Object) model(":models/cart.mdl") size(-36 -32 -10, 36 75 64) = obj_cart : "Cart" [] + +@PointClass base(Appearflags, Targetname, Target, Angles) model(":models/cattest.mdl") size(-160 -160 -0, 160 160 160) = obj_catapult2 : "Catapult" +[ + spawnflags(Flags) = + [ + 1 : "Not useable (PoP)" : 0 + ] + health(choices) : "Health" : 1000 = + [ + 0 : "Indestructible" + ] + wait(integer) : "Delay before reset" : 3 + speed(integer) : "Launch speed" : 300 + thingtype(choices) : "Material" : 2 = + [ + 0 : "Glass" + 1 : "Grey stone" + 2 : "Wood" + 3 : "Metal" + 4 : "Flesh" + 5 : "Fire" + 6 : "Clay" + 7 : "Leaves" + 8 : "Hay" + 9 : "Brown stone" + 10 : "Cloth" + 11 : "Wood & leaf" + 12 : "Wood & metal" + 13 : "Wood & stone" + 14 : "Metal & stone" + 15 : "Metal & cloth" + 16 : "Spider web" + //17 : "Glass" + 18 : "Ice" + 19 : "Clear glass" + 20 : "Red glass" + ] + //mass(integer) : "Mass" + //sounds + //soundtype +] + +@PointClass base(Object) model(":models/cauldron.mdl") size(-16 -16 0, 16 16 40) = obj_cauldron : "Cauldron" [] +@PointClass base(Object) model(":models/chair.mdl") size(-10 -10 -5, 10 10 40) = obj_chair : "Chair" [] +@PointClass base(Object) size(-100 -100 0, 100 100 200) = obj_chaos_orb : "Chaos orb" [] + +@PointClass base(Object) model(":models/chest1.mdl") size(-16 -16 0, 16 16 32) = obj_chest1 : "Chest #1" +[ + skin(choices) : "Skin" : 0 = + [ + 0 : "Generic texture" + 1 : "Roman texture" + ] +] +@PointClass base(Object) model(":models/chest2.mdl") size(-16 -16 0, 16 16 32) = obj_chest2 : "Chest #2" +[ + skin(choices) : "Skin" : 0 = + [ + 0 : "Generic texture" + 1 : "Meso texture" + 2 : "Egypt texture" + ] +] +@PointClass base(Object) model(":models/chest3.mdl") size(-16 -16 0, 16 16 32) = obj_chest3 : "Chest #3" [] + +@PointClass base(Object) model(":models/corps1.mdl") size(-32 -32 0, 32 32 10) = obj_corpse1 : "Corpse #1" +[ + skin(choices) : "Skin" : 0 = + [ + 0 : "Burnt, nude guy" + 1 : "Normal, nude guy" + 2 : "Diseased, nude guy" + 3 : "Wound, has pants" + ] +] +@PointClass base(obj_corpse1) model(":models/corps2.mdl") = obj_corpse2 : "Corpse #2" +[ + skin(choices) : "Skin" : 0 = + [ + 0 : "Shoulder and face wound" + 1 : "Clawed chest" + 2 : "Stomach wound" + 3 : "Just dead" + 4 : "Webbed" + ] +] + +@PointClass base(Object) model(":models/fence.mdl") size(-26 -26 0, 26 26 70) = obj_fence : "Fence" [] +@PointClass base(Object) model(":models/flag.mdl") size(-16 -16 0, 16 16 160) = obj_flag : "Flag" [] +@PointClass base(Object) model(":models/fountain.mdl") size(-24 -24 0, 24 24 80) = obj_fountain : "Fountain" [] +@PointClass base(Object) model(":models/hedge1.mdl") size(-16 -16 0, 16 16 80) = obj_hedge1 : "X-Mas tree" [] +@PointClass base(Object) model(":models/hedge2.mdl") = obj_hedge2: "Square, medium hedge" [] +@PointClass base(Object) model(":models/hedge3.mdl") = obj_hedge3 : "Tall, thin hedge" [] +@SolidClass base(Appearflags) = obj_ice : "Ice" +[ + spawnflags(Flags) = + [ + 1 : "No transparency" : 0 + ] + health(integer) : "Health" : 20 + friction(integer) : "Friction" : 0 + abslight(integer) : "Absolute light value" +] +@PointClass base(Object) size(-16 -40 0, 16 40 50) = obj_pew : "Pew" [] +@PointClass base(Object, Spawn) model(":models/plantgen.mdl") size(-10 -10 0, 10 10 20) = obj_plant_generic : "Generic plant" [] +@PointClass base(Object, Spawn) model(":models/plantmez.mdl") size(-10 -10 0, 10 10 40) = obj_plant_meso : "Meso plant" [] +@PointClass base(Object, Spawn) model(":models/plantrom.mdl") size(-24 -24 0, 24 24 90) = obj_plant_rome : "Roman plant" [] +@PointClass base(Object) model(":models/h_ass.mdl") size(-8 -8 0, 8 8 16) = obj_playerhead_assassin : "Assassin head" [] +@PointClass base(obj_playerhead_assassin) model(":models/h_cru.mdl") = obj_playerhead_crusader : "Crusader head" [] +@PointClass base(obj_playerhead_assassin) model(":models/h_nec.mdl") = obj_playerhead_necromancer : "Necro head" [] +@PointClass base(obj_playerhead_assassin) model(":models/h_ass.mdl") = obj_playerhead_paladin : "Paladin head" [] +@PointClass base(Object, Spawn) model(":models/pot1.mdl") size(-24 -24 0, 24 24 50) = obj_pot1 : "Pot #1" [] +@PointClass base(obj_pot1) model(":models/pot2.mdl") size(-16 -16 0, 16 16 40) = obj_pot2 : "Pot #2" [] +@PointClass base(obj_pot2) model(":models/pot3.mdl") = obj_pot3 : "Pot #3" [] +@PointClass base(Object) model(":models/seaweed.mdl") size(-8 -8 0, 8 8 32) = obj_seaweed : "Sea weed" [] +@PointClass base(Object) model(":models/skull.mdl") size(-8 -8 0, 8 8 16) = obj_skull : "Skull" [] +@PointClass base(Object) model(":models/skllstk1.mdl") size(-16 -16 0, 16 16 40) = obj_skullstick : "1 skull, stick" [] +@PointClass base(Object) model(":models/skllstk2.mdl") size(-16 -16 0, 16 16 40) = obj_skull_stick2 : "2 skulls, stick" [] +@PointClass base(Object) model(":models/anglstat.mdl") size(-60 -60 0, 60 60 120) = obj_statue_angel : "Angel" [] +@PointClass base(Object) model(":models/athena.mdl") size(-30 -30 0, 30 30 90) = obj_statue_athena : "Athena" [] +@PointClass base(Object) model(":models/caesar.mdl") size(-24 -24 0, 24 24 90) = obj_statue_caesar : "Caesar" [] +@PointClass base(Object) model(":models/king.mdl") size(-30 -30 0, 30 30 120) = obj_statue_king : "King" [] +@PointClass base(Object) model(":models/lion.mdl") size(-56 -14 0, 56 14 60) = obj_statue_lion : "Lion" [] +@PointClass base(Object) model(":models/mars.mdl") size(-30 -30 0, 30 30 80) = obj_statue_mars : "Mars" [] +@PointClass base(Object) model(":models/mumstatu.mdl") size(-16 -16 0, 16 16 160) = obj_statue_mummy : "Mummy" [] +@PointClass base(Object) model(":models/muhead.mdl") size(-16 -16 -26, 16 16 160) = obj_statue_mummy_head : "Mummy head"[] +@PointClass base(Object) model(":models/neptune.mdl") size(-30 -30 0, 30 30 100) = obj_statue_neptune : "Neptune" [] +@PointClass base(Object) model(":models/olmec1.mdl") size(-40 -40 0, 40 40 130) = obj_statue_olmec : "Olmec???" [] +@PointClass base(Object) model(":models/snkstatu.mdl") size(-16 -16 0, 16 16 80) = obj_statue_snake : "Snake" [] +@PointClass base(Object) size(-44 -44 0, 44 44 90) = obj_statue_snake_coil : "Coiling snake" [] +@PointClass base(Object) model(":models/tutstatu.mdl") size(-36 -36 0, 36 36 248) = obj_statue_tut : "Tut" [] +@PointClass base(Object) model(":models/sword.mdl") size(-16 -16 -8, 16 16 8) = obj_sword : "Sword" [] +@PointClass base(Object) model(":models/tombstn1.mdl") size(-24 -24 0, 24 24 60) = obj_tombstone1 : "Cross tombstone" [] +@PointClass base(Object) model(":models/tombstn2.mdl") size(-16 -16 0, 16 16 40) = obj_tombstone2 : "Rounded tombstone" [] +@PointClass base(Object) model(":models/tree.mdl") size(-42 -42 0, 42 42 160) = obj_tree : "Leaveless tree" [] +@PointClass base(Object) model(":models/tree2.mdl") size(-140 -140 -16, 140 140 220) = obj_tree2 : "Normal tree" [] +@PointClass base(Object) model(":models/webs.mdl") size(-25 -25 -25, 25 25 25) = obj_webs : "Spider web" +[ + spawnflags(Flags) = + [ + 1 : "Solid" : 0 + 2 : "Animate" : 0 + 4 : "Weak" : 0 + 8 : "Touch & move" : 0 + 16 : "Flat" : 0 + 32 : "No transparency" : 0 + ] + skin(choices) : "Skin" : 0 = + [ + 0 : "Many little webs" + 1 : "Corner web" + 2 : "Cobwebs" + 3 : "Giant web" + 4 : "Big web (15x)" + ] + v_angle(string) : "Angle of web (x y z)" : "0 0 0" +] + +// +// PoP Objects! +// + +@PointClass base(Object) size(-8 -8 -0, 8 8 8) = obj_book_o_the_dead : "Book (PoP)" [] +@PointClass base(Object) size(-32 -32 -128, 32 32 0) = obj_chinese_kite_lamp : "Kite lamp (PoP)" [] +@PointClass base(Object) size(-8 -8 -96, 8 8 0) = obj_chinese_sign : "Sign (PoP)" [] //size(-8 -72 -96, 8 72 0) +@PointClass base(Object) size(-0 -48 -0, 96 48 120) = obj_demon_statue : "Demon statue (PoP)" [] +@PointClass base(Object) size(-20 -20 -0, 20 20 80) = obj_samurai : "Samurai statue (PoP)" [] +@PointClass base(Object) size(-16 -16 -0, 16 16 72) = obj_shiva : "Shiva (PoP)" [] +@PointClass base(Object) size(-12 -12 -0, 12 12 12) = obj_skeleton : "Skeleton (PoP)" [] //size(-40 -12 -0, 40 12 12) +@PointClass base(Object) size(-32 -32 -0, 32 32 120) = obj_skeleton_throne : "Skeleton on throne (PoP)" [] +@PointClass base(Object) size(-40 -56 -0, 40 56 64) = obj_snow_corner : "Snow corner (PoP)" [] +@PointClass base(Object) size(-24 -32 -0, 24 32 16) = obj_snow_pile : "Snow pile (PoP)" [] +@PointClass base(Object) size(-0 -80 -0, 40 80 40) = obj_snow_wall : "Snow wall (PoP)" [] +@PointClass base(Object) size(-32 -32 -16, 32 32 32) = obj_stalagmite1 : "Stalagmite1 (PoP)" [] +@PointClass base(Object) size(-40 -40 -24, 40 40 24) = obj_stalagmite2 : "Stalagmite2 (PoP)" [] +@PointClass base(Object) size(-16 -16 -0, 16 16 64) = obj_statue_dragon_lion : "Dragon statue (PoP)" [] //size(-40 -16 -0, 40 16 64) +@PointClass base(Object) size(-8 -8 -64, 8 8 64) = obj_talking_door : "Talking door (PoP)" [] + +// +// Entities! +// + +@PointClass base(Appearflags, Targetname) size(-8 -8 -8, 8 8 8) = path_corner : "Monster and train path" +[ + spawnflags(Flags) = + [ + 1 : "Synch" : 0 + ] + target(target_destination) : "Next path_corner" + angles(string) : "Angles (x y z)" + wait(integer) : "Wait (-1 stops, -2 destroys)" : 0 + speed(integer) : "Speed" + anglespeed(integer) : "Rotation speed" +] + +@PointClass base(Monster) model(":models/sheep.mdl") size(-8 -8 0, 8 8 32) = player_sheep : "Sheep" +[ + spawnflags(Flags) = + [ + 1 : "No not move" : 0 + ] +] + +@SolidClass base(Appearflags, Targetname) = plaque : "Readable plaque" +[ + spawnflags(Flags) = + [ + 1 : "Invisible" : 0 + 2 : "Deactivated" : 0 + 4 : "No LoS (PoP)" : 0 + 8 : "Not solid (PoP)" : 0 + ] + message(integer) : "String index #" + //noise1(string) : "Noise (dir/sound.wav)" +] + +@PointClass base(Appearflags, Targetname, Target) size(-8 -8 -8, 8 8 16) = puzzle_piece : "Puzzle piece" +[ + spawnflags(Flags) = + [ + 1 : "Spawn" : 0 + 2 : "Floating" : 0 + 4 : "Auto get" : 0 + ] + puzzle_id(string) : "Puzzle id" //Model name also works (without path or .mdl) + message(string) : "Message" + netname(string) : "Puzzle piece name" //Name of piece, displayed when picked up + style(integer) : "Light Style" +] + +@PointClass base(Appearflags, Targetname) size(-8 -8 -8, 8 8 8) = puzzle_static_piece : "Static puzzle piece" +[ + puzzle_id(string) : "Puzzle id" //Model name also works (without path or .mdl) + lifespan(integer) : "Lifespan" +] + +// +// Rider Stuff! +// + +@PointClass base(Appearflags, Targetname) size(-55 -55 -24, 55 55 100) = rider_death : "Death!" +[ + spawnflags(Flags) = + [ + 1 : "Trigger wait" : 0 + ] + target(string) : "Start spot on next map" + map(string) : "Next map after killing" +] +@PointClass base(rider_death) = rider_famine : "Famine!" [] +@PointClass base(rider_death) = rider_pestilence : "Pestilence!" [] +@PointClass base(rider_death) size(-50 -50 -24, 50 50 100) = rider_war : "War!" [] + +@PointClass base(Appearflags, Targetname) = rider_path : "Rider path" +[ + path_id(string) : "Path id" + next_path_1(string) : "Next path 1" + next_path_2(string) : "Next path 2" + next_path_3(string) : "Next path 3" + next_path_4(string) : "Next path 4" + next_path_5(string) : "Next path 5" + next_path_6(string) : "Next path 6" +] +@SolidClass base(Appearflags, Targetname) = rider_quake : "Rider quake" +[ + model(string) : "Model" + rt_chance(integer) : "Chance of triggering (0-1)" + abslight(integer) : "Absolute light value" +] +@PointClass base(Appearflags, Targetname) = rider_quake_center : "Rider quake center" +[ + rt_chance(integer) : "Chance of triggering (0-1)" +] +@SolidClass base(Appearflags, Targetname, Target) = rider_trigger_multiple : "Rider trigger multiple" +[ + rt_chance(integer) : "Chance of triggering (0-1)" : 1 +] +@SolidClass base(rider_trigger_multiple) = rider_trigger_once : "Rider trigger once" +[ + model(string) : "Model" +] + +// +// Rings! +// + +@PointClass base(Item) size(-8 -8 -44, 8 8 20) = Ring_Flight : "Ring o' flight" [] +@PointClass base(Ring_Flight) = Ring_Regeneration : "Ring o' regeneration" [] +@PointClass base(Ring_Flight) = Ring_Turning : "Ring o' turning" [] +@PointClass base(Ring_Flight) = Ring_WaterBreathing : "Ring o' water breathing" [] + +// +// Entities! +// + +@PointClass base(Appearflags) = sound_ambient : "Ambient sound" +[ + soundtype(choices) : "Sound" : 4 = //9-15 Do not work properly + [ + 1 : "Windmill" + 2 : "Sewer water sound" + 3 : "Dripping water, no echo" + 4 : "Subtle sky/wind" + 5 : "Crickets / night sounds" + 6 : "Birds" + 7 : "Raven caw" + 8 : "Rocks falling" + //9 : "Lava bubble" + //10 : "Water gurgle" + //11 : "Metal" + //12 : "Pounding" + //13 : "Moans and screams" + //14 : "Creaking" + //15 : "Chain rattling" + ] +] + +@PointClass base(Appearflags, Targetname) size(-10 -10 -8, 10 10 8) = sound_maker : "Triggerable sound" +[ + soundtype(choices) : "Sound" : 1 = + [ + 1 : "Bell ringing" + 2 : "Organ music" + 3 : "Tomb sound" + ] + delay(integer) : "Delay" +] + +@PointClass base(Appearflags, Targetname) size(-8 -8 -8, 8 8 8) = target_null : "Null target" [] + +@PointClass base(Appearflags, Targetname) size(-8 -8 -8, 8 8 8) = teleport_buddha : "Praevus teleport (PoP)" +[ + cnt(integer) : "Cnt" : 0 +] + +// +// Traps! +// + +@PointClass base(Appearflags, Targetname, Target) size(-8 -8 -8, 8 8 8) = trap_fireball : "Triggerable fireball" +[ + spawnflags(Flags) = + [ + 1 : "Once per trigger" : 0 //(aka trigger only) + ] + wait(integer) : "Time between firings" : 1 + dmg(integer) : "Damage" : 10 +] +@PointClass base(Appearflags, Targetname, Target) size(-8 -8 -8, 8 8 8) = trap_lightning : "Lightning" +[ + spawnflags(Flags) = + [ + 1 : "Track" : 0 //Tracks player + 2 : "Once" : 0 //Fires only once + ] + noise(choices) : "Sounds" : 2 = + [ + 1 : "No sound" + 2 : "Lightning" + ] + wait(integer) : "Time between shots" : 1 + dmg(integer) : "Damage" + //aflag(integer) : "Radius limit" //Crashes to console when used +] +@PointClass base(Appearflags, Targetname, Angles) size(-8 -8 -8, 8 8 8) = trap_shooter : "Shooter" +[ + //spawnflags(Flags) = //These do not work, same for the spikeshooter below + //[ + // 1 : "Super spike" : 0 + // 2 : "Laser" : 0 + //] + wait(integer) : "Time between shots" : 1 + nextthink(integer) : "Delay before start" +] +@PointClass base(Appearflags, Targetname, Angles) size(-8 -8 -8, 8 8 8) = trap_spikeshooter : "Shooter" +[ + //spawnflags(Flags) = + //[ + // 1 : "Super spike" : 0 + // 2 : "Laser" : 0 + //] + wait(integer) : "Time between shots" : 1 + nextthink(integer) : "Delay before start" +] +@PointClass base(Appearflags, Targetname) size(-8 -8 -8, 8 8 8) = trap_spikeshooter_spray : "Shooter" +[ + wait(integer) : "Time between shots" : 1 + nextthink(integer) : "Delay before start" +] + +// +// Triggers! +// + +@BaseClass base(Appearflags, Targetname, Target) = Trigger +[ + killtarget(target_destination) : "KillTarget" + netname(string) : "Netname" + aflag(integer) : "Order" + wait(integer) : "Wait" : 2 + health(integer) : "Health" + delay(integer) : "Delay before trigger" + message(string) : "Message" + style(integer) : "Light Style" +] + +@baseclass = Puzzles +[ + spawnflags(Flags) = + [ + 16 : "Remove puzzle" : 0 + 32 : "No puzzle" : 0 + ] + puzzle_piece_1(string) : "Puzzle Piece 1" + puzzle_piece_2(string) : "Puzzle Piece 2" + puzzle_piece_3(string) : "Puzzle Piece 3" + puzzle_piece_4(string) : "Puzzle Piece 4" + no_puzzle_msg(string) : "No puzzle message" +] + +@baseclass = Triggerflags +[ + spawnflags(Flags) = + [ + 1 : "No touch" : 0 + 2 : "Monster touch" : 0 + 4 : "Push touch" : 0 + 8 : "Deactivated" : 0 + 64 : "Light toggle" : 0 + 128 : "Light start low" : 0 + ] +] + +@SolidClass base(Trigger, Puzzles) = trigger_activate : "Activate" +[ + spawnflags(Flags) = + [ + 1 : "Once" : 0 + 2 : "Relay" : 0 + 8 : "Deactivated" : 0 + ] + soundtype(choices) : "Sound" : 2 = + [ + 0 : "No sound" + 1 : "Secret" + 2 : "Bell" + 3 : "Metal" + ] +] + +@SolidClass base(Trigger) = trigger_attack : "Trigger on weapon fire" [] + +@SolidClass base(Trigger) = trigger_changelevel : "Changes level" +[ + spawnflags(Flags) = + [ + 1 : "No intermission" : 0 + //2 : "End of unit" : 0 + //4 : "End of episode" : 0 + ] + map(string) : "Map name" +] +@SolidClass base(Appearflags, Targetname, Target) = trigger_check : "Check" //Not triggered by players +[ + killtarget(target_destination) : "KillTarget" + netname(string) : "Netname" + aflag(integer) : "Order" + health(integer) : "Health" + delay(integer) : "Delay before trigger" + message(string) : "Message" + style(integer) : "Light Style" + failtarget(target_destination) : "Fail target (PoP)" + wait(integer) : "Wait (PoP)" +] + +@SolidClass base(Trigger) = trigger_combination_assign : "Combination assign" +[ + mangle(string) : "Mangle (x y z)" +] + +@SolidClass base(Appearflags, Targetname, Target) = trigger_control : "Ballista control" [] + +@SolidClass base(Trigger) = trigger_counter : "Counter" +[ + spawnflags(Flags) = + [ + 1 : "No message" : 0 + 2 : "Ordered" : 0 + 4 : "Always return" : 0 + 8 : "Deactivated" : 0 + ] + msg2(integer) : "Count fail message" + puzzle_id(target_destination) : "Count fail target" + count(integer) : "Number of triggers - 1" + mangle(string) : "Mangle (x1 x2 x3)" +] + +@SolidClass base(Trigger) = trigger_counter_reset : "Counter reset" +[ + spawnflags(Flags) = + [ + 1 : "No touch" : 0 + 2 : "Monster touch" : 0 + 4 : "Push touch" : 0 + 8 : "Deactivated" : 0 + 16 : "Remove puzzle" : 0 + 32 : "No puzzle" : 0 + 64 : "Light toggle" : 0 + 128 : "Light start low" : 0 + ] +] + +@SolidClass base(Trigger) = trigger_crosslevel : "Cross level trigger" +[ + spawnflags(Flags) = + [ + 1 : "Trigger 1" : 0 + 2 : "Trigger 2" : 0 + 4 : "Trigger 3" : 0 + 8 : "Trigger 4" : 0 + 16 : "Trigger 5" : 0 + 32 : "Trigger 6" : 0 + 64 : "Trigger 7" : 0 + 128 : "Trigger 8" : 0 + ] + map(string) : "Map" +] +@SolidClass base(trigger_crosslevel) = trigger_crosslevel_target : "Crosslevel trigger target" [] + +@SolidClass base(trigger_activate) = trigger_deactivate : "Deactivate" [] + +@SolidClass base(Appearflags, Targetname, Target) = trigger_deathtouch : "Removes whatever it touches (PoP)" +[ + spawnflags(Flags) = + [ + 1 : "No touch" : 0 + 2 : "Any player" : 0 + 4 : "Gib" : 0 + 8 : "Deactivated" : 0 + ] + th_die(integer) : "Death type" +] + +@PointClass base(Appearflags, Targetname, Target) = trigger_hub_intermission : "Trigger hub intermission (PoP)" +[ + map(string) : "Map" +] + +@SolidClass base(Appearflags, Targetname) = trigger_hurt : "Hurt brush" [ + spawnflags(Flags) = + [ + 1 : "Player only (PoP)" : 0 + 2 : "Monster only (PoP)" : 0 + 8 : "Deactivated (PoP)" : 0 + ] + dmg(integer) : "Damage" : 5 + level(integer) : "Minimum health (PoP)" + wait(integer) : "Delay between damage(PoP)" : 1 +] + +@PointClass base(Appearflags, Targetname, Target) size(-8 -8 -8, 8 8 8) = trigger_interval : "Interval trigger" +[ + spawnflags(Flags) = + [ + 8 : "Deactivated" : 0 + ] + killtarget(target_destination) : "KillTarget" + netname(string) : "Netname" + delay(integer) : "Delay before trigger" + wait(integer) : "Wait" +] + +@SolidClass base(Appearflags, Targetname, Target) = trigger_message_transfer : "Message transferer" +[ + message(string) : "Message (required)" : "139" +] + +@SolidClass base(Appearflags, Targetname) = trigger_monsterjump : "Monster jumper" +[ + spawnflags(Flags) = + [ + 1 : "Deactivated (PoP)" : 0 + ] + speed(integer) : "Speed forward" : 200 + height(integer) : "Speed upwards" : 200 + wait(integer) : "Wait" : 0 +] + +@SolidClass base(Appearflags, Targetname, Target, Trigger, Triggerflags, Puzzles) = trigger_multiple : "Multiple trigger" +[ + soundtype(choices) : "Sounds" : 0 = + [ + 0 : "No sound" + 1 : "Secret" + 2 : "Bell" + 3 : "Large switch" + ] +] + +@SolidClass base(Appearflags) = trigger_no_friction : "Removes friction" +[ + style(integer) : "Light toggle style (33 - 63)" + lightvalue1(integer) : "Low light value" : 0 + lightvalue2(integer) : "High light value" : 11 + fadespeed(integer) : "Fade speed (0.5)" : 0 +] + +@PointClass base(Appearflags, Targetname, Target) = trigger_objective : "Trigger objective (PoP)" +[ + spawnflags(Flags) = + [ + 1 : "Force on" : 0 + 2 : "Force off" : 0 + ] + frags(integer) : "Objective (0-63)" +] + +@SolidClass base(Appearflags, Targetname, Target, Trigger, Puzzles, trigger_multiple) = trigger_once : "Single trigger" [] + +@SolidClass base(Appearflags, Targetname) = trigger_push : "Push" +[ + spawnflags(Flags) = + [ + 1 : "Push once" : 0 + ] + speed(integer) : "Speed of push" + angles(string) : "Angle of push (X Y Z)" +] + +@PointClass base(Appearflags, Targetname, Target) = trigger_quake : "Quake" +[ + spawnflags(Flags) = + [ + 1 : "Do damage" : 0 + 2 : "Multiple" : 0 + //8 : "Deactivated" : 0 //Quake doesn't appear to function properly after activating + ] + killtarget(target_destination) : "KillTarget" + message(string) : "Message" + items(integer) : "Radius of quake" + dmg(integer) : "Damage" : 5 + lifespan(integer) : "Duration" : 2 + wait(integer) : "Delay before quake" : 1 +] + +@PointClass base(Appearflags, Targetname, Target) size(-8 -8 -8, 8 8 8) = trigger_relay : "Relay" +[ + killtarget(target_destination) : "KillTarget" + netname(string) : "Netname" + wait(integer) : "Wait" + delay(integer) : "Delay before trigger" + message(string) : "Message" + fadespeed(integer) : "Fade speed" + style(integer) : "Light Style" +] + +@SolidClass base(Appearflags, Targetname) = trigger_setskill : "Set skill level (PoP)" +[ + noise(choices) : "Skill level" : 1 = + [ + 0 : "Easy" + 1 : "Medium" + 2 : "Hard" + 3 : "Nightmare!" + ] +] + +@SolidClass base(Appearflags, Targetname, Target) = trigger_stop : "Trigger stop (PoP)" +[ + spawnflags(Flags) = + [ + 1 : "No touch" : 0 + ] + //wait(integer) : "Wait" //Crashes to console when used +] + + +@SolidClass base(Appearflags, Targetname, Target) = trigger_teleport : "Trigger teleport" +[ + spawnflags(flags) = + [ + 1 : "Player only" : 0 + 2 : "Silent" : 0 + 4 : "Deactivated" : 0 + ] +] + +// +// Weather! +// + +@SolidClass base(Appearflags) = weather_dust : "Dusty area" +[ + color(integer) : "Color" : 101 +] + +@PointClass base(Appearflags, Targetname) = weather_lightning_end : "End of lightning bolt" [] +@PointClass base(Appearflags, Targetname, Target) = weather_lightning_start : "Beginning of lighting" +[ + spawnflags(Flags) = + [ + 1 : "Start off" : 0 + 2 : "Thunder sound" : 0 + ] + noise(choices) : "Sounds" : 2 = + [ + 1 : "No sound" + 2 : "Lightning" + ] + wait(choices) : "Time between strikes" : -1 = + [ + -1 : "Once per trigger" + ] + lifespan(integer) : "Duration" + dmg(integer) : "Damage" +] + +@SolidClass base(Appearflags) = weather_rain : "Rain area" +[ + spawnflags(Flags) = + [ + 1 : "Fall straight" : 0 + 2 : "No splat" : 0 + ] + color(integer) : "Base color" : 414 + counter(integer) : "Density" : 300 + wait(integer) : "Frequency (0.1)" : 0 + soundtype(choices) : "Sounds" : 1 = + [ + 0 : "Rain" + 1 : "Drip" + ] +] + +@SolidClass base(Appearflags) = weather_snow : "Snow (PoP)" +[ + spawnflags(Flags) = + [ + 1 : "Fluffy" : 0 + 2 : "Mixed" : 0 + 4 : "Half bright" : 0 + 8 : "No melt" : 0 + 16 : "In bounds" : 0 + 32 : "No translucent" : 0 + ] + counter(integer) : "Density" : 100 + speed(integer) : "Falling speed" : 200 + anglespeed(integer) : "Lateral movement" : 125 + movedir(string) : "Blow direction (# # #)" +] + +@PointClass base(Appearflags, Targetname) size(-8 -8 -8, 8 8 8) = weather_sunbeam_end : "End of sunbeam" [] +@PointClass base(Appearflags, Targetname, Target) = weather_sunbeam_start : "Start of sunbeam" +[ + spawnflags(Flags) = + [ + 1 : "Start off" : 0 + ] + noise(choices) : "Sounds" : 2 = + [ + 1 : "No sound" + 2 : "Buzzing" + ] + wait(choices) : "Time between strikes" : -1 = + [ + -1 : "Once per trigger" + ] + lifespan(integer) : "Duration" + dmg(integer) : "Damage" +] + +// +// Weapons! +// + +@PointClass base(Appearflags, Targetname, Target) size(-8 -8 -44, 8 8 20) = wp_weapon2 : "Weapon 2" +[ + spawnflags(Flags) = + [ + 1 : "Floating" : 0 + ] + message(string) : "Message" + style(integer) : "Light Style" +] +@PointClass base(wp_weapon2) = wp_weapon3 : "Weapon 3" [] +@PointClass base(wp_weapon2) = wp_weapon4_head : "Weapon 4 head" [] +@PointClass base(wp_weapon2) = wp_weapon4_staff : "Weapon 4 staff" [] + +@SolidClass base() = func_detail: "ericw compilers - not calculated in VIS" +[] + +@SolidClass base() = func_detail_illusionary: "ericw compilers - not solid and bit calculated in VIS" +[] + +@SolidClass base() = func_group: "ericw compilers" +[] \ No newline at end of file diff --git a/tools/trenchbroom/games/Hexen2/Icon.png b/tools/trenchbroom/games/Hexen2/Icon.png new file mode 100644 index 0000000..b75ad2d Binary files /dev/null and b/tools/trenchbroom/games/Hexen2/Icon.png differ diff --git a/tools/trenchbroom/games/Hexen2/palette.lmp b/tools/trenchbroom/games/Hexen2/palette.lmp new file mode 100644 index 0000000..52d79f4 Binary files /dev/null and b/tools/trenchbroom/games/Hexen2/palette.lmp differ diff --git a/tools/trenchbroom/games/Kingpin/GameConfig.cfg b/tools/trenchbroom/games/Kingpin/GameConfig.cfg new file mode 100644 index 0000000..1a3845a --- /dev/null +++ b/tools/trenchbroom/games/Kingpin/GameConfig.cfg @@ -0,0 +1,285 @@ +{ + "version": 9, + "name": "Kingpin", + "icon": "Icon.png", + "fileformats": [ { "format": "Quake2" }, { "format": "Quake2 (Valve)"} ], + "filesystem": { + "searchpath": "main", + "packageformat": { "extension": ".pak", "format": "idpak" } + }, + "materials": { + "root": "textures", + "extensions": [".tga"], + "palette": "pics/colormap.pcx" + }, + "entities": { + "definitions": [ "kingpin.fgd" ], + "defaultcolor": "0.6 0.6 0.6 1.0" + }, + "tags": { + "brush": [ + { + "name": "Trigger", + "attribs": [ "transparent" ], + "match": "classname", + "pattern": "trigger*", + "material": "0_trigger" + }, + { + "name": "Weather", + "attribs": [ "transparent" ], + "match": "classname", + "pattern": "elements*" + } + ], + "brushface": [ + { + "name": "Clip", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "0_clip" + }, + { + "name": "Skip", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "0_skip" + }, + { + "name": "Hint", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "0_hint" + }, + { + "name": "Detail", + "match": "contentflag", + "flags": [ "detail" ] + }, + { + "name": "Liquid", + "match": "contentflag", + "flags": [ "lava", "slime", "water" ] + }, + { + "name": "Sound", + "match": "surfaceflag", + "flags": [ "water", "concrete", "fabric", "gravel", "metal", "metal lite", "tin", "tile", "wood" ] + } + ] + }, + "faceattribs": { + "surfaceflags": [ + { + "name": "light", + "description": "Emit light from the surface, brightness is specified in the 'value' field" + }, + { + "name": "slick", + "description": "The surface is slippery" + }, + { + "name": "sky", + "description": "The surface is sky, the texture will not be drawn, but the background sky box is used instead" + }, + { + "name": "warp", + "description": "The surface warps (like water textures do)" + }, + { + "name": "trans33", + "description": "The surface is 33% transparent" + }, + { + "name": "trans66", + "description": "The surface is 66% transparent" + }, + { + "name": "flowing", + "description": "The texture wraps in a downward 'flowing' pattern (warp must also be set)" + }, + { + "name": "nodraw", + "description": "Used for non-fixed-size brush triggers and clip brushes" + }, + { + "name": "hint", + "description": "Make a primary bsp splitter" + }, + { + "name": "skip", + "description": "Completely ignore, allowing non-closed brushes" + }, + { + "name": "specular", + "description": " " + }, + { + "name": "diffuse", + "description": " " + }, + { + "name": "alpha", + "description": "alpha texture" + }, + { + "name": "mirror", + "description": " " + }, + { + "name": "wndw33", + "description": " " + }, + { + "name": "wndw66", + "description": " " + }, + { "unused": true }, + { "unused": true }, + { "unused": true }, + { + "name": "water", + "description": "water sound" + }, + { + "name": "concrete", + "description": "concrete sound" + }, + { + "name": "fabric", + "description": "fabric sound" + }, + { + "name": "gravel", + "description": "gravel sound" + }, + { + "name": "metal", + "description": "metal sound" + }, + { + "name": "metal lite", + "description": "metal light sound" + }, + { + "name": "tin", + "description": "tin sound" + }, + { + "name": "tile", + "description": "tile sound" + }, + { + "name": "wood", + "description": "wood sound" + }, + { + "name": "reflect fake", + "description": " " + }, + { + "name": "reflect light", + "description": " " + } + ], + "contentflags": [ + { + "name": "solid", + "description": "Default for all brushes" + }, // 1 + { + "name": "window", + "description": "Brush is a window (not really used)" + }, // 2 + { + "name": "aux", + "description": "Unused by the engine" + }, // 4 + { + "name": "lava", + "description": "The brush is lava" + }, // 8 + { + "name": "slime", + "description": "The brush is slime" + }, // 16 + { + "name": "water", + "description": "The brush is water" + }, // 32 + { + "name": "mist", + "description": "The brush is non-solid" + }, // 64 + { + "name": "fence", + "description": "The brush is solid" + }, // 128 + { "unused": true }, // 256 + { "unused": true }, // 512 + { "unused": true }, // 1024 + { "unused": true }, // 2048 + { "unused": true }, // 4096 + { "unused": true }, // 8192 + { "unused": true }, // 16384 + { "unused": true }, // 32768 + { + "name": "playerclip", + "description": "Player cannot pass through the brush (other things can)" + }, // 65536 + { + "name": "monsterclip", + "description": "Monster cannot pass through the brush (player and other things can)" + }, // 131072 + { + "name": "current_0", + "description": "Brush has a current in direction of 0 degrees" + }, + { + "name": "current_90", + "description": "Brush has a current in direction of 90 degrees" + }, + { + "name": "current_180", + "description": "Brush has a current in direction of 180 degrees" + }, + { + "name": "current_270", + "description": "Brush has a current in direction of 270 degrees" + }, + { + "name": "current_up", + "description": "Brush has a current in the up direction" + }, + { + "name": "current_dn", + "description": "Brush has a current in the down direction" + }, + { + "name": "origin", + "description": "Special brush used for specifying origin of rotation for rotating brushes" + }, + { + "name": "monster", + "description": "Purpose unknown" + }, + { + "name": "corpse", + "description": "Purpose unknown" + }, + { + "name": "detail", + "description": "Detail brush" + }, + { + "name": "translucent", + "description": "Use for opaque water that does not block vis" + }, + { + "name": "ladder", + "description": "Brushes with this flag allow a player to move up and down a vertical surface" + } + ] + }, + "softMapBounds":"-4096 -4096 -4096 4096 4096 4096" +} \ No newline at end of file diff --git a/tools/trenchbroom/games/Kingpin/Icon.png b/tools/trenchbroom/games/Kingpin/Icon.png new file mode 100644 index 0000000..787a7f5 Binary files /dev/null and b/tools/trenchbroom/games/Kingpin/Icon.png differ diff --git a/tools/trenchbroom/games/Kingpin/colormap.pcx b/tools/trenchbroom/games/Kingpin/colormap.pcx new file mode 100644 index 0000000..b3f0c76 Binary files /dev/null and b/tools/trenchbroom/games/Kingpin/colormap.pcx differ diff --git a/tools/trenchbroom/games/Kingpin/kingpin.fgd b/tools/trenchbroom/games/Kingpin/kingpin.fgd new file mode 100644 index 0000000..d62d1d9 --- /dev/null +++ b/tools/trenchbroom/games/Kingpin/kingpin.fgd @@ -0,0 +1,2567 @@ + +// +// Kingpin game definition file (.fgd) +// last update: march 7 2019 +// +// written by FREDZ / fredz@kingpin.info +// email me with improvements and suggestions +// +// special thanks to: ACC for the SPMOD def files and autolycus for the Quake2.fgd. +// + +// base marker definitions +@baseclass = Appearflags [ + spawnflags(Flags) = + [ + 256 : "Not in Easy" : 0 + 512 : "Not in Normal" : 0 + 1024 : "Not in Hard" : 0 + 2048 : "Not in Deathmatch" : 0 + 4096 : "Not in Coop" : 0 + ] +] + +@baseclass = Angle [ angle(angle) : "Angle direction" ] +@baseclass = Targetname [ targetname(target_source) : "This entity's ID" ] +@baseclass = Target [ target(target_destination) : "Target" ] +@baseclass = Killtarget [ killtarget(target_destination) : "ID of the entity to delete when triggered" ] + +@SolidClass = worldspawn : "World entity" +[ + episode(string) : "Episode number" + sky(string) : "Environment map name (skybox), also used for reflection" + sounds(integer) : "Music cd track number" + gravity(integer) : "Gravity" : 800 + light(integer) : "Set a low value to LIGHT the entire map without using individual bulbs" + message(string) : "Map name" + fogdensity(string) : "Fog density for opengl cards" + fogdensity2(string) : "Fog density for 3dfx cards" + fogval(string) : "RGB values of fog for opengl cards" + fogval2(string) : "RGB values of fog for 3dfx cards" + _sun_light(string) : "Set sun brightness" + _sun_target(string) : "Defines sun yaw and pitch pointing to a spotlight target" + _sun_angle(string) : "Defines sun yaw and pitch manually (0 to 360) (-90 to 90)" + _sun_vector(string) : "Defines sun yaw and pitch using a X Y Z direction vector" + _sun_color(string) : "Defines sun color in scalar R G B" + _sun_diffuse(string) : "Diffuse light brightness" + _sun_difwait(string) : "Diffuse light attenuation" + _sun_ambient(string) : "Set sun ambient brightness" + _sun_surface(string) : "Set sun surface brightness" +] + + + +@SolidClass = ai_boundary : "Character will abort pursuing player when touching this brush. Will take cover until the player is out of view, then return to guarding position (if character has been assigned one)." +[ + moral(choices) : "Moral -- 1 to 7 = coward to psychotic" : 0 = + [ + 0 : "Random" + 1 : "Coward" + 2 : "Happy" + 3 : "Normal" + 4 : "Aggressive" + 5 : "Beserk" + 6 : "Heroic" + 7 : "Psychotic" + ] + cast_group(choices) : "Gang number" : 0 = + [ + 0 : "Neutral" + 1 : "Friendly" + 2 : "Enemy" + ] +] +@PointClass size(-16 -16 -24, 16 16 48) color(128 128 255) = ai_combat_spot : "A good place to go to get a vantage point during fighting. Same code as ai_safespot." [] +@SolidClass = ai_event_follow : "Client touching this brush will become a leader to all other characters in line of sight, that have the same cast_group as the brush (cast_group must be greater than 0 to work)." +[ + cast_group(choices) : "Gang number" : 0 = + [ + 0 : "Warning: ai_event_follow without a valid cast_group" + 1 : "Friendly" + 2 : "Enemy" + ] +] +@SolidClass = ai_event_hostile : "Character touching this brush will become a hostile enemy to all other characters in line of sight, that have the same cast_group as the brush (cast_group must be greater than 0 to work)." +[ + cast_group(choices) : "Gang number" : 0 = + [ + 0 : "Warning: ai_event_hostile without a valid cast_group" + 1 : "Friendly" + 2 : "Enemy" + ] +] +@PointClass size(-16 -16 -24, 16 16 48) color(128 128 255) = ai_guard : "Set a cast's 'guard_target' to the 'targetname' of this entity. That character will then guard this location. Same code as ai_safespot just no guard_radius." +[ + guard_radius(integer) : "Max guarding radius" : 512 +] +@SolidClass base(Appearflags, Target) = ai_locked_door : "A character touching this brush will check the targeted door to see if it is closed. If so, the character will head towards the specified path_corner_cast. Example use: guiding AI characters away from a locked door" +[ + pathtarget(string) : "path_corner_cast's ID to head for" +] +@PointClass size(-16 -16 -24, 16 16 48) color(128 128 255) = ai_safespot : "A good place to go to get a vantage point during fighting. Same code as ai_combat_spot." [] +@SolidClass = ai_territory : "This entity marks the boundary of a gang's territory. A character touching this will be deemed inside the gang's territory. This means war if sighted. Point the angle in the direction of the territory. This lets the AI know if the character is walking into or out of the territory." +[ + cast_group(choices) : "Gang number" : 2 = + [ + 0 : "Neutral" + 1 : "Friendly" + 2 : "Enemy" + ] + angle(angle) : "Points to the direction of the territory" + radius(integer) : "Distance from brush before the player will be attacked" : 512 + moral(choices) : "Moral -- 1 to 7 = coward to psychotic" : 4 = + [ + 0 : "Random" + 1 : "Coward" + 2 : "Happy" + 3 : "Normal" + 4 : "Aggressive" + 5 : "Beserk" + 6 : "Heroic" + 7 : "Psychotic" + ] +] +@SolidClass base(Appearflags, Target) = ai_trigger_character : "When the player touches this brush, the targeted character will start following it's path_corner_cast." +[ + cast_group(choices) : "Gang number" : 2 = + [ + 0 : "Neutral" + 1 : "Friendly" + 2 : "Enemy" + ] +] + + +@baseclass base(Appearflags, Targetname, Target, Killtarget, Angle) size(-16 -16 -16, 16 16 16) color(77 77 255) = AmmoClass [] +@PointClass base(AmmoClass) studio("models/pu_icon/hmgclip/tris.md2") = ammo_308 : "Bullets clip for the heavy submachine gun (weapon_heavymachinegun), 30 bullets per clip (max: 90)." [] +@PointClass base(AmmoClass) studio("models/pu_icon/pclip/tris.md2") = ammo_bullets : "Bullets clip for the pistol (weapon_pistol, weapon_spistol) and Thompson submachine gun (weapon_tommygun), 20 bullets per clip (max: 200)." [] +@PointClass base(AmmoClass) studio("models/pu_icon/tgclip/tris.md2") = ammo_cylinder : "Bullets for the Thompson submachine gun (weapon_tommygun) or pistol (weapon_pistol, weapon_spistol), 50 bullets per drum (max: 200)." [] +@PointClass base(AmmoClass) studio("models/pu_icon/flametank/tris.md2") = ammo_flametank : "Gaz for the flame thrower (weapon_flamethrower), 50 units of gaz per tank (max: 200)" [] +@PointClass base(AmmoClass) studio("models/pu_icon/grenade/tris.md2") = ammo_grenades : "Grenades for the grenade launcher (weapon_grenadelauncher), 3 per box (max: 12)." [] +@PointClass base(AmmoClass) studio("models/pu_icon/rocket/tris.md2") = ammo_rockets : "Missiles for the rocket launcher (weapon_bazooka), 5 missiles per box (max: 25)." [] +@PointClass base(AmmoClass) studio("models/pu_icon/shotgun_shell/tris.md2") = ammo_shells : "Shells box for the shotgun (weapon_shotgun), 10 shells per box (max: 100)." [] + + + +@PointClass base(Appearflags, Target, Killtarget, Angle) size(-16 -16 -24, 16 16 48) color(255 128 0) studio("models\actors\bitch\head.mdx;models\actors\bitch\body.mdx;models\actors\bitch\legs.mdx") = cast_bitch : "One-handed weapon chick (gender: female)" +[ + head(choices) : "Head shape" :0 = + [ + 0 : "Normal" + 2 : "Pony Tail" + ] + art_skins(string) : "Head -- torso -- legs skin number (always three digits)" + scale(integer) : "Model scale -- 0 to 1" : 1 + cast_group(choices) : "Gang number" : 0 = + [ + 0 : "Neutral" + 1 : "Friendly" + 2 : "Enemy" + ] + currentcash(integer) : "Money (negative value to hire)" + localteam(string) : "Gang name" + health(integer) : "Health points" : 100 + name(string) : "Character's name" + acc(integer) : "Accuracy" : 2 + cal(integer) : "Weapon caliber" : 3 + moral(choices) : "Moral" = + [ + 0 : "Random" + 1 : "Coward" + 2 : "Happy" + 3 : "Normal" + 4 : "Aggressive" + 5 : "Beserk" + 6 : "Heroic" + 7 : "Psychotic" + ] + item(string) : "Item name to drop on death" + guard_target(string) : "Link to ai_guard entity" + combattarget(string) : "Link to path_corner_cast" + deathtarget(string) : "Target to trigger on death" + leader_target(string) : "Link to another gang member" + health_target(string) : "Target to health threshold events 1 (trigger or run to)" + health_threshold(string) : "Must be set if health_target is used" + health_target2(string) : "Target to health threshold events 2 (trigger or run to)" + health_threshold2(string) : "Must be set if health_target2 is used" + health_target3(string) : "Target to health threshold events 3 (trigger or run to)" + health_threshold3(string) : "Must be set if health_target3 is used" + gun_noise_delay(integer) : "React delay befor hear gun and thake action" + aiflags(string) : "AI flags" + spawnflags(flags) = + [ + 2 : "Trigger Spawn" : 0 + 32 : "Immediate Follow Path" : 0 + 64 : "Melee" : 0 + 128 : "No Shadow" : 0 + ] +] +@PointClass base(Appearflags, Angle) size(-24 -24 -24, 24 24 48) color(255 128 0) studio("models\actors\bum_sit\head.mdx;models\actors\bum_sit\body.mdx;models\actors\bum_sit\legs.mdx") = cast_bum_sit : "A bum, should always be neutral (gender: male)." +[ + art_skins(string) : "Head -- torso -- legs skin number (always three digits)" + currentcash(integer) : "Money" + scale(integer) : "Model scale -- 0 to 1" : 1 + cast_group(choices) : "Gang number" : 0 = + [ + 0 : "Neutral" + 1 : "Friendly" + 2 : "Enemy" + ] + health(integer) : "Health points" : 100 + name(string) : "Character's name" + count(Flags) = + [ + 0 : "None" + 1 : "Cigar" + 2 : "Fedora" + 4 : "Stetson" + 8 : "Cap" + ] + spawnflags(flags) = + [ + 2 : "Trigger Spawn" : 0 + ] +] +@PointClass base(Appearflags, Target, Killtarget, Angle) size(-16 -16 -16, 16 16 22) color(255 128 0) studio("models\actors\enemy_dog\enemy_dog.mdx") = cast_dog : "Dog." +[ + skin(choices) : "Skin" : 1 = + [ + 1 : "Black Pitbull" + 2 : "Rottweiler" + ] + currentcash(integer) : "Money" + scale(integer) : "Model scale -- 0 to 1" : 1 + cast_group(choices) : "Gang number" : 0 = + [ + 0 : "Neutral" + 1 : "Friendly" + 2 : "Enemy" + ] + health(integer) : "Health points" : 100 + guard_target(string) : "Link to ai_guard entity" + combattarget(string) : "Link to path_corner_cast" + deathtarget(string) : "Target to trigger on death" + leader_target(string) : "Link to another gang member" + health_target(string) : "Target to health threshold events 1 (trigger or run to)" + health_threshold(string) : "Must be set if health_target is used" + health_target2(string) : "Target to health threshold events 2 (trigger or run to)" + health_threshold2(string) : "Must be set if health_target2 is used" + health_target3(string) : "Target to health threshold events 3 (trigger or run to)" + health_threshold3(string) : "Must be set if health_target3 is used" + gun_noise_delay(integer) : "React delay befor hear gun and thake action" + aiflags(string) : "AI flags" + spawnflags(flags) = + [ + 2 : "Trigger Spawn" : 0 + ] +] +@PointClass base(Appearflags, Target, Killtarget, Angle) size(-16 -16 -24, 16 16 48) color(255 128 0) studio("models\actors\punk\head.mdx;models\actors\punk\body.mdx;models\actors\punk\legs.mdx") = cast_punk : "Two handed weapon thug (gender: male)." +[ + art_skins(string) : "Head -- torso -- legs skin number (always three digits)" + head(choices) : "Head shape" : 0 = + [ + 0 : "Normal" + 1 : "Bald" + 2 : "Weld Head" + ] + count(Flags) = + [ + 0 : "None" + 1 : "Cigar" + 2 : "Fedora" + 4 : "Stetson" + 8 : "Cap" + ] + scale(integer) : "Model scale -- 0 to 1" : 1 + cast_group(choices) : "Gang number" : 0 = + [ + 0 : "Neutral" + 1 : "Friendly" + 2 : "Enemy" + ] + currentcash(integer) : "Money (negative value to hire)" + localteam(string) : "Gang name" + health(integer) : "Health points" : 100 + name(string) : "Character's name" + acc(integer) : "Accuracy" : 2 + cal(integer) : "Weapon caliber" : 3 + moral(choices) : "Moral" = + [ + 0 : "Random" + 1 : "Coward" + 2 : "Happy" + 3 : "Normal" + 4 : "Aggressive" + 5 : "Beserk" + 6 : "Heroic" + 7 : "Psychotic" + ] + item(string) : "Item name to drop on death" + guard_target(string) : "Link to ai_guard entity" + combattarget(string) : "Link to path_corner_cast" + deathtarget(string) : "Target to trigger on death" + leader_target(string) : "Link to another gang member" + health_target(string) : "Target to health threshold events 1 (trigger or run to)" + health_threshold(string) : "Must be set if health_target is used" + health_target2(string) : "Target to health threshold events 2 (trigger or run to)" + health_threshold2(string) : "Must be set if health_target2 is used" + health_target3(string) : "Target to health threshold events 3 (trigger or run to)" + health_threshold3(string) : "Must be set if health_target3 is used" + gun_noise_delay(integer) : "React delay befor hear gun and thake action" + aiflags(string) : "AI flags" + spawnflags(flags) = + [ + 1 : "Flash Light" : 0 + 2 : "Trigger Spawn" : 0 + 4 : "Flamethrower" : 0 + 8 : "Bazooka" : 0 + 16 : "HMG" : 0 + 32 : "Immediate Follow Path" : 0 + 64 : "Tommygun" : 0 + 128 : "Grenade" : 0 + 8192 : "Shotgun" : 0 + ] +] +@PointClass base(Appearflags, Target, Killtarget, Angle) size(-16 -16 -24, 16 16 48) color(255 128 0) studio("models\actors\runt\head.mdx;models\actors\runt\body.mdx;models\actors\runt\legs.mdx") = cast_runt : "One handed weapon runt (gender: male)." +[ + art_skins(string) : "Head -- torso -- legs skin number (always three digits)" + count(Flags) = + [ + 0 : "None" + 1 : "Cigar" + 2 : "Fedora" + 4 : "Stetson" + 8 : "Cap" + ] + scale(integer) : "Model scale -- 0 to 1" : 1 + cast_group(choices) : "Gang number" : 0 = + [ + 0 : "Neutral" + 1 : "Friendly" + 2 : "Enemy" + ] + currentcash(integer) : "Money (negative value to hire)" + localteam(string) : "Gang name" + health(integer) : "Health points" : 100 + name(string) : "Character's name" + acc(integer) : "Accuracy" : 2 + cal(integer) : "Weapon caliber" : 3 + moral(choices) : "Moral" = + [ + 0 : "Random" + 1 : "Coward" + 2 : "Happy" + 3 : "Normal" + 4 : "Aggressive" + 5 : "Beserk" + 6 : "Heroic" + 7 : "Psychotic" + ] + item(string) : "Item name to drop on death" + guard_target(string) : "Link to ai_guard entity" + combattarget(string) : "Link to path_corner_cast" + deathtarget(string) : "Target to trigger on death" + leader_target(string) : "Link to another gang member" + health_target(string) : "Target to health threshold events 1 (trigger or run to)" + health_threshold(string) : "Must be set if health_target is used" + health_target2(string) : "Target to health threshold events 2 (trigger or run to)" + health_threshold2(string) : "Must be set if health_target2 is used" + health_target3(string) : "Target to health threshold events 3 (trigger or run to)" + health_threshold3(string) : "Must be set if health_target3 is used" + gun_noise_delay(integer) : "React delay befor hear gun and thake action" + aiflags(string) : "AI flags" + spawnflags(flags) = + [ + 2 : "Trigger Spawn" : 0 + 32 : "Immediate Follow Path" : 0 + 64 : "Melee" : 0 + 128 : "No Shadow" : 0 + ] +] +@PointClass base(Appearflags, Target, Killtarget) size(-16 -16 -24, 16 16 48) color(255 128 0) studio("models\actors\shorty\head.mdx;models\actors\shorty\body.mdx;models\actors\shorty\legs.mdx") = cast_shorty : "Two handed weapon runt (gender: male)." +[ + art_skins(string) : "Head -- torso -- legs skin number (always three digits)" + scale(integer) : "Model scale -- 0 to 1" : 1 + cast_group(choices) : "Gang number" : 0 = + [ + 0 : "Neutral" + 1 : "Friendly" + 2 : "Enemy" + ] + currentcash(integer) : "Money (negative value to hire)" + localteam(string) : "Gang name" + health(integer) : "Health points" : 100 + name(string) : "Character's name" + acc(integer) : "Accuracy" : 2 + cal(integer) : "Weapon caliber" : 3 + moral(choices) : "Moral" = + [ + 0 : "Random" + 1 : "Coward" + 2 : "Happy" + 3 : "Normal" + 4 : "Aggressive" + 5 : "Beserk" + 6 : "Heroic" + 7 : "Psychotic" + ] + item(string) : "Item name to drop on death" + guard_target(string) : "Link to ai_guard entity" + combattarget(string) : "Link to path_corner_cast" + deathtarget(string) : "Target to trigger on death" + leader_target(string) : "Link to another gang member" + health_target(string) : "Target to health threshold events 1 (trigger or run to)" + health_threshold(string) : "Must be set if health_target is used" + health_target2(string) : "Target to health threshold events 2 (trigger or run to)" + health_threshold2(string) : "Must be set if health_target2 is used" + health_target3(string) : "Target to health threshold events 3 (trigger or run to)" + health_threshold3(string) : "Must be set if health_target3 is used" + gun_noise_delay(integer) : "React delay befor hear gun and thake action" + aiflags(string) : "AI flags" + spawnflags(flags) = + [ + 1 : "Flash Light" : 0 + 2 : "Trigger Spawn" : 0 + 4 : "Flamethrower" : 0 + 8 : "Bazooka" : 0 + 16 : "HMG" : 0 + 32 : "Immediate Follow Path" : 0 + 64 : "Tommygun" : 0 + 128 : "Grenade" : 0 + 8192 : "Shotgun" : 0 + ] +] +@PointClass base(Appearflags, Target, Killtarget, Angle) size(-16 -16 -24, 16 16 48) color(255 128 0) studio("models\actors\thug\head.mdx;models\actors\thug\body.mdx;models\actors\thug\legs.mdx") = cast_thug : "One handed weapon thug (gender: male)." +[ + art_skins(string) : "Head -- torso -- legs skin number (always three digits)" + head(choices) : "Head shape" : 0 = + [ + 0 : "Normal" + 1 : "Bald" + 2 : "Weld Head" + ] + count(Flags) = + [ + 0 : "None" + 1 : "Cigar" + 2 : "Fedora" + 4 : "Stetson" + 8 : "Cap" + ] + scale(integer) : "Model scale -- 0 to 1" : 1 + cast_group(choices) : "Gang number" : 0 = + [ + 0 : "Neutral" + 1 : "Friendly" + 2 : "Enemy" + ] + currentcash(integer) : "Money (negative value to hire)" + localteam(string) : "Gang name" + health(integer) : "Health points" : 100 + name(string) : "Character's name" + acc(integer) : "Accuracy" : 2 + cal(integer) : "Weapon caliber" : 3 + moral(choices) : "Moral" = + [ + 0 : "Random" + 1 : "Coward" + 2 : "Happy" + 3 : "Normal" + 4 : "Aggressive" + 5 : "Beserk" + 6 : "Heroic" + 7 : "Psychotic" + ] + item(string) : "Item name to drop on death" + guard_target(string) : "Link to ai_guard entity" + combattarget(string) : "Link to path_corner_cast" + deathtarget(string) : "Target to trigger on death" + leader_target(string) : "Link to another gang member" + health_target(string) : "Target to health threshold events 1 (trigger or run to)" + health_threshold(string) : "Must be set if health_target is used" + health_target2(string) : "Target to health threshold events 2 (trigger or run to)" + health_threshold2(string) : "Must be set if health_target2 is used" + health_target3(string) : "Target to health threshold events 3 (trigger or run to)" + health_threshold3(string) : "Must be set if health_target3 is used" + gun_noise_delay(integer) : "React delay befor hear gun and thake action" + aiflags(string) : "AI flags" + spawnflags(flags) = + [ + 2 : "Trigger Spawn" : 0 + 32 : "Immediate Follow Path" : 0 + 64 : "Melee" : 0 + 128 : "No Shadow" : 0 + ] +] +@PointClass base(Appearflags, Angle) size(-16 -16 -24, 16 16 48) color(255 128 0) studio("models\actors\thug_sit\head.mdx;models\actors\thug_sit\body.mdx;models\actors\thug_sit\legs.mdx") = cast_thug_sit : "Guy with the pistol, should always be neutral (gender: male)." +[ + art_skins(string) : "Head -- torso -- legs skin number (always three digits)" + head(choices) : "Head shape" : 0 = + [ + 0 : "Normal" + 1 : "Bald" + 2 : "Weld Head" + ] + scale(integer) : "Model scale -- 0 to 1" : 1 + cast_group(choices) : "Gang number" : 0 = + [ + 0 : "Neutral" + 1 : "Friendly" + 2 : "Enemy" + ] + count(Flags) = + [ + 0 : "None" + 1 : "Cigar" + 2 : "Fedora" + 4 : "Stetson" + 8 : "Cap" + ] + health(integer) : "Health points" : 100 + name(string) : "Character's name" + gun_noise_delay(integer) : "React delay befor hear gun and thake action" + aiflags(string) : "AI flags" + spawnflags(flags) = + [ + 2 : "Trigger Spawn" : 0 + 32 : "Immediate Follow Path" : 0 + 64 : "Melee" : 0 + 128 : "No Shadow" : 0 + ] +] +@PointClass base(Appearflags, Target, Killtarget, Angle) size(-16 -16 -24, 16 16 48) color(255 128 0) studio("models\actors\whore\head.mdx;models\actors\whore\body.mdx;models\actors\whore\legs.mdx") = cast_whore : "Two handed weapon chick (gender: female)." +[ + art_skins(string) : "Head -- torso -- legs skin number (always three digits)" + head(choices) : "Head shape" : 0 = + [ + 0 : "Normal" + 1 : "Bald" + 2 : "Pony Tail" + ] + scale(integer) : "Model scale -- 0 to 1" : 1 + cast_group(choices) : "Gang number" : 0 = + [ + 0 : "Neutral" + 1 : "Friendly" + 2 : "Enemy" + ] + currentcash(integer) : "Money (negative value to hire)" + localteam(string) : "Gang name" + health(integer) : "Health points" : 100 + name(string) : "Character's name" + acc(integer) : "Accuracy" : 2 + cal(integer) : "Weapon caliber" : 3 + moral(choices) : "Moral" = + [ + 0 : "Random" + 1 : "Coward" + 2 : "Happy" + 3 : "Normal" + 4 : "Aggressive" + 5 : "Beserk" + 6 : "Heroic" + 7 : "Psychotic" + ] + item(string) : "Item name to drop on death" + guard_target(string) : "Link to ai_guard entity" + combattarget(string) : "Link to path_corner_cast" + deathtarget(string) : "Target to trigger on death" + leader_target(string) : "Link to another gang member" + health_target(string) : "Target to health threshold events 1 (trigger or run to)" + health_threshold(string) : "Must be set if health_target is used" + health_target2(string) : "Target to health threshold events 2 (trigger or run to)" + health_threshold2(string) : "Must be set if health_target2 is used" + health_target3(string) : "Target to health threshold events 3 (trigger or run to)" + health_threshold3(string) : "Must be set if health_target3 is used" + gun_noise_delay(integer) : "React delay befor hear gun and thake action" + aiflags(string) : "AI flags" + spawnflags(flags) = + [ + 1 : "Flash Light" : 0 + 2 : "Trigger Spawn" : 0 + 4 : "Flamethrower" : 0 + 8 : "Bazooka" : 0 + 16 : "HMG" : 0 + 32 : "Immediate Follow Path" : 0 + 64 : "Tommygun" : 0 + 128 : "Grenade" : 0 + 8192 : "Shotgun" : 0 + ] +] + + +@PointClass size(-16 -16 -16, 16 16 16) color(128 0 255) = dm_cashspawn : "Spawn location for cash in Grab da Loot games." +[ + angle(string) : "Direction to project cash upon spawning" + speed(integer) : "Projection's speed" + type(string) : "cashroll or cashbag (cashbag takes longer to spawn)" +] +@PointClass size(-47 -6 -100, 47 6 100) color(128 0 255) + studio( + {{ + style & 2 -> "models/props/flag/flag1.md2", + style & 1 -> "models/props/flag/flag3.md2", + "models/props/flag/tris.md2" + }} + ) = dm_props_banner : "Temp banner for teamplay." +[ + scale(float) : "Model scale" : "1.0" + style(choices) : "Team that this banner belongs to (1 or 2)" : 0 = + [ + 0 : "dm_props_banner has invalid style, should be 1 or 2." + 1 : "Dragons" + 2 : "Nikki's Boyz" + ] +] +@PointClass size(-12 -12 -16, 12 12 12) color(128 0 255) studio("models/pu_icon/money/money_lg.md2") = dm_safebag : "Bag that holds the money in the safe." +[ + style(choices) : "Team that this bag belongs to (1 or 2)" : 0 = + [ + 0 : "dm_safebag has invalid style, should be 1 or 2." + 1 : "Dragons" + 2 : "Nikki's Boyz" + ] +] + + +@SolidClass = elements_raincloud : "Rain falls from this invisible cloud at random points; the center of the cloud to ground trace determines the drop fall distance. Cloud can only be rectangular." +[ + fxdensity(integer) : "Total number of drops in the sky, 1 to 1000" : 400 + firetype(integer) : "Type of drops -- 0 = rain, 1 = drip" : 0 +] +@SolidClass = elements_snowcloud : "Snow falls from this invisible cloud at random points; the center of the cloud to ground trace determines the drop fall distance. Cloud can only be rectangular." +[ + fxdensity(integer) : "Total number of drops in the sky, 1 to 1000" : 400 +] + + + +@SolidClass base(Appearflags, Targetname) = func_areaportal : "Area portal (Vis blocker), Toggle visibility portal's when activated, usually enclosed in the middle of a door so when it is closed, the area beyond is not rendered (the door must target this entity)" [] +@SolidClass base(Appearflags, Target, Targetname, Killtarget, Angle) = func_button : "When a button is touched, it moves some distance in the direction of its angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again." +[ + speed(integer) : "Moving speed)" : 40 + accel(integer) : "Acceleration (default=speed)" + decel(integer) : "Deceleration (default=speed)" + wait(integer) : "Wait before return (default=1) (set to -1=never return)" + lip(integer) : "Lip" : 4 + pathtarget(string) : "Entity to trigger when an entity that has this path_corner targeted touches it" + health(string) : "If set, the button is shootable" + sounds(choices) : "Sounds" : 0 = + [ + 0 : "Audible" + 1 : "Silent" + 2 : "world/switches/butn2.wav" + 3 : "world/switches/valve.wav" + 4 : "world/switches/wheel.wav" + 5 : "world/switches/console switch.wav" + 6 : "world/switches/pushbutton.wav" + 7 : "world/switches/thunk switch.wav" + 8 : "world/switches/wall.wav" + ] + message(string) : "Activation message" + spawnflags(flags) = + [ + 1 : "Auto Open" : 0 + 2 : "Onoff" : 0 + 4 : "No Monster" : 0 + ] +] +@PointClass base(Appearflags, Targetname) color(0 0 255) size(-8 -8 -8, 8 8 8) = func_clock : "Clock: target a target_string with this. The default is to be a time of day clock. If START_OFF, this entity must be used before it starts" +[ + spawnflags(Flags) = + [ + 1 : "Timer Up" : 0 + 2 : "Timer Down" : 0 + 4 : "Start Off" : 0 + 8 : "Multi Use" : 0 + ] + count(integer) : "Clock Count" + pathtarget(string) : "Target" + style(choices) : "Style" : 0 = + [ + 0 : "xx" + 1 : "xx:xx" + 2 : "xx:xx:xx" + ] +] +@SolidClass base(Appearflags, Targetname) = func_conveyor : "Conveyors are stationary brushes that move what's on them. The brush should have a surface with at least one current content enabled." +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + 2 : "Toggle" : 0 + ] + speed(integer) : "Speed" : 100 +] +@SolidClass base(Appearflags, Targetname, Target, Killtarget, Angle) = func_door : "A sliding door." +[ + spawnflags(Flags) = + [ + 1 : "Start Open" : 0 + 4 : "Crusher" : 0 + 8 : "No Monsters" : 0 + 16 : "Animated" : 0 + 32 : "Toggle" : 0 + 64 : "Animated Fast" : 0 + 128 : "Surf2 Alpha" : 0 + ] + target2(string) : "Point to an ai_safespot's ID (for lockpicking purpose), can also be used as an alternate targetname field." + team(string) : "Trigger every door with the same team name" + message(string) : "Message printed once when the door is touched if it is a trigger door" + health(integer) : "If set, door must be shot open" + speed(integer) : "Movement speed" : 100 + accel(string) : "Acceleration (default=speed)" + decel(string) : "Deceleration (default=speed)" + wait(integer) : "wait before returning (-1 = never return)" : 3 + lip(integer) : "Lip remaining at end of move" : 8 + dmg(integer) : "Damage to inflict when blocked" : 2 + Key(choices) : "Key number required to unlock" : 0 = + [ + -1 : "Trigger Unlock" + 0 : "Default" + 1 : "Store Room Key" + 2 : "Electrical Room Key" + 3 : "Chem Plant Key" + 4 : "Bridge Key" + 5 : "Shipyard Key" + 6 : "Warehouse Key" + 7 : "Shop Key" + 8 : "Ticket Key" + 9 : "Office Key" + 10 : "Key10" + ] + sounds(choices) : "Sounds" : 2 = + [ + 0 : "Audible" + 1 : "Silent" + 2 : "Metal Sliding" + 3 : "Wooden Swinging #1" + 4 : "Metal Swingingt" + 5 : "Metal Sliding Train" + 6 : "Metal Rolling" + 7 : "Metal Swing-up Garage Door" + 8 : "Wooden Swinging #2" + 9 : "Wooden Drawer" + 10 : "Metal Drawer" + ] +] + +@SolidClass base(Appearflags, Targetname, Target, Killtarget, Angle) = func_door_rotating : "Rotating Door: You need to have an origin brush as part of this entity. The center of that brush will be the point around which it is rotated. It will rotate around the Z axis by default. You can check either the X_AXIS or Y_AXIS box to change that" +[ + spawnflags(Flags) = + [ + 1 : "Start Open" : 0 + 2 : "Reverse" : 0 + 4 : "Surf2 Alpha" : 0 + 8 : "No Monsters" : 0 + 16 : "Animated" : 0 + 32 : "Toggle" : 0 + 64 : "X Axis" : 0 + 128 : "Y Axis" : 0 + ] + target2(string) : "Point to an ai_safespot's ID (for lockpicking purpose), can also be used as an alternate targetname field." + team(string) : "Trigger every door with the same team name" + distance(integer) : "How many degrees the door will be rotated." + message(string) : "Message printed once when the door is touched if it is a trigger door" + health(integer) : "If set, door must be shot open" + speed(integer) : "Movement speed" : 100 + wait(integer) : "wait before returning (-1 = never return)" : 3 + dmg(integer) : "Damage to inflict when blocked" : 2 + style(choices) : "Style" : 0 = + [ + 0 : "Rotate away from it's activator" + 1 : "Fixed rotation " + ] + Key(choices) : "Key number required to unlock" : 0 = + [ + -1 : "Trigger Unlock" + 0 : "Default" + 1 : "Store Room Key" + 2 : "Electrical Room Key" + 3 : "Chem Plant Key" + 4 : "Bridge Key" + 5 : "Shipyard Key" + 6 : "Warehouse Key" + 7 : "Shop Key" + 8 : "Ticket Key" + 9 : "Office Key" + 10 : "Key10" + ] + sounds(choices) : "Sounds" : 2 = + [ + 0 : "Audible" + 1 : "Silent" + 2 : "Metal Sliding" + 3 : "Wooden Swinging #1" + 4 : "Metal Swingingt" + 5 : "Metal Sliding Train" + 6 : "Metal Rolling" + 7 : "Metal Swing-up Garage Door" + 8 : "Wooden Swinging #2" + 9 : "Wooden Drawer" + 10 : "Metal Drawer" + ] +] +@SolidClass base(Appearflags, Targetname, Target, Killtarget, Angle) = func_door_secret : "A secret door. Slide back and then to the side." +[ + spawnflags(Flags) = + [ + 1 : "Always shoot" : 0 + 2 : "1st Left" : 0 + 4 : "1st Down" : 0 + ] + dmg(integer) : "Damage to inflic when blocked" : 2 + wait(integer) : "How long to hold in the open position, stay forever if '-1'" : 5 + health(integer) : "Strength, must be shot-open if set." + message(string) : "Message printed once when the door is touched if it is a trigger door" +] +@SolidClass base(Appearflags, Targetname, Target, Killtarget) = func_explosive : "Any brush that you want to explode or break apart. If you want an explosion, set dmg and it will do a radius explosion of that amount at the center of the bursh." +[ + spawnflags(Flags) = + [ + 1 : "Trigger Spawn" : 0 + 2 : "Animated" : 0 + 4 : "Animated Fast" : 0 + 8 : "Surf2 Alpha" : 0 + ] + health(integer) : "Hit points " : 100 + mass(integer) : "Amount of debris (debris)" : 75 + dmg(integer) : "How much radius damage should be done." : 0 + fxdensity(integer) : "Size of explosion 1 to 100" : 10 + style(choices) : "Styles" = + [ + "glass" : "Glass debris" + "wood" : "Wood debris" + "metal" : "Metal debris" + ] +] +@SolidClass = func_group : "Used to group brushes together just for editor convenience." [] +@SolidClass base(Appearflags, Targetname) = func_killbox : "Kills everything inside when fired, irrespective of protection." [] +@SolidClass base(Appearflags, Target, Killtarget)= func_lift : "Lifts are moving platforms that players and ai_characters can ride (up and down only!!). The targets origin specifies the min point of the train at each corner. The train spawns at the first target it is pointing at. If the train is the target of a button or trigger, it will not begin moving until activated. A button is required for the AI to use." +[ + speed(integer) : "Movement speed" : 100 + dmg(integer) : "Damage to inflict when blocked (BLOCK_STOPS default=0)" : 100 + noise(sound) : "looping sound to play when the train is in motion" + target2(string) : "ID string for attached button" + spawnflags(flags) = + [ + 1 : "Start On" : 0 + 2 : "Toggle" : 0 + 4 : "Block Stops" : 0 + ] +] + +@SolidClass base(Appearflags, Targetname) = func_object : "Solid bmodel, will fall if its support is removed" +[ + spawnflags(Flags) = + [ + 1 : "Trigger Spawn" : 0 + 2 : "Animated" : 0 + 4 : "Animated Fast" : 0 + ] + dmg(integer) : "Damages inflicted to crushed entities" : 100 +] +@SolidClass base(Appearflags, Target) color(255 128 0) = func_object_repair : "Object to be repaired." +[ + delay(integer) : "Time in seconds for sparks to occur" : 1 +] +@SolidClass base(Appearflags, Targetname) = func_plat : "Platform: Plats are always rendered in the extended position when compiling map, so they will light correctly. If the plat is the target of another trigger or button, it will start out disabled in the extended position until it is triggered, when it will lower and become a normal plat." +[ + spawnflags(Flags) = + [ + 1 : "Plat Low Trigger" : 0 + ] + speed(integer) : "Moving Speed" : 20 + accel(integer) : "Acceleration" : 5 + decel(integer) : "Deceleration" : 5 + lip(integer) : "Lip remaining after move" : 8 + height(integer) : "Movement distance" + dmg(integer) : "Damages when blocked" : 2 + wait(integer) : "Time to wait before trigger" +] +@SolidClass base(Appearflags, Targetname) = func_rotating : "Rotating brush: You need to have an origin brush as part of this entity. The center of that brush will be the point around which it is rotated. It will rotate around the Z axis by default. You can check either the X_AXIS or Y_AXIS spawnflag to change the rotation axe." +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + 2 : "Reverse" : 0 + 4 : "X Axis" : 0 + 8 : "Y Axis" : 0 + 16 : "Pain on Touch" : 0 + 32 : "Block Stops" : 0 + 64 : "Animated" : 0 + 128 : "Animated Fast" : 0 + ] + speed(integer) : "Moving speed" : 100 + dmg(integer) : "Damage when blocked" : 2 +] +@PointClass base(Appearflags, Targetname, Target, Killtarget) color(76 25 153) size(-8 -8 -8, 8 8 8) = func_timer : "Timer: Automatic trigger, can be activated, toggle." +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + ] + wait(integer) : "Base time between triggering all targets, in seconds" : 1 + random(integer) : "Wait variance (+/-), in seconds" : 0 + delay(integer) : "Delay before first firing when activated" : 0 + pausetime(integer) : "Additional delay used only the very first time, if START_ON is set" +] +@SolidClass base(Appearflags, Targetname, Target, Killtarget) = func_train : "Moving platform: Trains are moving platforms that players can ride. The targets origin specifies the min point of the train at each corner. The train spawns at the first target it is pointing at. If the train is the target of a button or trigger, it will not begin moving until activated." +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + 2 : "Toggle" : 0 + 4 : "Block Stops" : 0 + 8 : "Surf2 Alpha" : 0 + ] + speed(integer) : "Movement speed" : 100 + dmg(integer) : "Damage to inflict when blocked (BLOCK_STOPS default=100)" : 2 + noise(sound) : "Sound (path/file.wav)" +] +@SolidClass base(Appearflags, Targetname, Target, Killtarget) = func_train_rotating : "Trains are moving platforms that players can ride. The targets origin specifies the min point of the train at each corner. The train spawns at the first target it is pointing at. If the train is the target of a button or trigger, it will not begin moving until activated." +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + 2 : "Toggle" : 0 + 4 : "Block Stops" : 0 + 8 : "Surf2 Alpha" : 0 + ] + speed(integer) : "Movement speed" : 100 + dmg(integer) : "Damage to inflict when blocked (BLOCK_STOPS default=100)" : 2 + noise(sound) : "Sound (path/file.wav)" + reactdelay(integer) : "Sound length in second" : 1 +] +@SolidClass base(Appearflags, Targetname) = func_wall : "Solid Wall: This is just a solid wall if not inhibited. Wall is always present by default, unless TRIGGER_SPAWN is set -- When triggered, the wall will shift from OFF to ON (or ON to OFF)." +[ + spawnflags(Flags) = + [ + 1 : "Trigger Spawn" : 0 + 2 : "Toggle" : 0 + 4 : "Start On" : 0 + 8 : "Animated" : 0 + 16 : "Animated Fast" : 0 + 32 : "Surf2 Alpha" : 0 + ] +] +@SolidClass base(Appearflags, Targetname, Angle) = func_water : "Movable water brush, must be targeted to operate. Use a non-water texture at your own risk." +[ + spawnflags(Flags) = + [ + 1 : "Start Open" : 0 + 2 : "Translucent" : 0 + ] + speed(integer) : "Movement speed" : 25 + wait(integer) : "Wait before returning (TOGGLE)" : -1 + lip(integer) : "Lip remaining at end of move" : 0 + sounds(Choices) : "Sounds" : 1 = + [ + 0 : "No Sounds" + 1 : "Water" + 2 : "Water" + ] + +] + + +@PointClass base(Appearflags, Targetname, Target, Killtarget, Angle) size(-16 -16 -16, 16 16 16) color(179 77 102) studio("models\pu_icon\coolmod\tris.md2") = hmg_mod_cooling : "Cooling sleeves for the heavy submachine gun (weapon_heavymachinegun), increase rate of fire, lasts 30 shots before breaking up." [] + + + +@baseclass base(Appearflags, Targetname) size(-4 -4 -4, 4 4 4) color(0 128 0) = NullClass [] +@PointClass base(NullClass) = info_null : "Used as a positional target for spotlights, etc. If no targetname it's removed." [] +@PointClass base(NullClass) = info_notnull : "Used as a positional target for lightning." [] + +// +// player start, deathmatch, coop, deathmatch intermission +// + +@baseclass base(Appearflags, Targetname) size(-16 -16 -24, 16 16 32) color(0 255 0) = PlayerClass [] +@PointClass base(PlayerClass, Angle) = info_player_start : "The normal starting point for a level." [] +@PointClass base(PlayerClass, Angle) = info_player_deathmatch : "Spawning point for players in deathmatch games." +[ + style(choices) : "Team number for Teamplay" : 0 = + [ + 0 : "None" + 1 : "Dragons" + 2 : "Nikki's Boyz" + ] +] +@PointClass base(PlayerClass, Angle) = info_player_coop : "Spawning point for AI gang members in a single-player game. Every single-player map should contain two of these near to the client's start point." [] +@PointClass base(PlayerClass, Angle) = info_player_intermission : "Potential intermission viewpoint for deathmatch games." +[ + angles(string) : "Pitch, yaw and roll view direction." +] + + +@baseclass base(Appearflags, Targetname, Target, Killtarget, Angle) size(-16 -16 -16, 16 16 16) color(77 77 255) = ItemClass [] +@PointClass base(ItemClass) studio("models/pu_icon/armor_head/armor_head.md2") = item_armor_helmet : "Armor: Helmet armor, light." [] +@PointClass base(ItemClass) studio("models/pu_icon/armor_head/armor_head_hd.md2") = item_armor_helmet_heavy : "Armor: Helmet armor, heavy." [] +@PointClass base(ItemClass) studio("models/pu_icon/armor/tris.md2") = item_armor_jacket : "Armor: Jacket armor, light." [] +@PointClass base(ItemClass) studio("models/pu_icon/armor/armorhdtop.md2") = item_armor_jacket_heavy : "Armor: Jacket armor, heavy." [] +@PointClass base(ItemClass) studio("models/pu_icon/armor_lo/armor_lo.md2") = item_armor_legs : "Armor: Legs armor, light." [] +@PointClass base(ItemClass) studio("models/pu_icon/armor_lo/armor_lo_hd.md2") = item_armor_legs_heavy : "Armor: Legs armor, heavy." [] +@PointClass base(ItemClass) studio("models/pu_icon/adrenaline/tris.md2") = item_adrenaline : "Health: adrenaline (totally restores health)." [] +@PointClass base(ItemClass) studio("models/pu_icon/battery/tris.md2") = item_battery : "Pickup item: bike battery ('Battery')." [] +@PointClass base(ItemClass) studio("models/pu_icon/money/money_lg.md2") = item_cashbaglarge : "Cash the player can pick up." +[ + currentcash(string) : "Set amount of cash in the bag" +] +@PointClass base(ItemClass) studio("models/pu_icon/money/money_sm.md2") = item_cashbagsmall : "Cash the player can pick up." +[ + currentcash(string) : "Set amount of cash in the bag" +] +@PointClass base(ItemClass) studio("models/pu_icon/cash/tris.md2") = item_cashroll : "Cash the player can pick up." +[ + currentcash(string) : "Set amount of cash in the bag" +] +@PointClass base(ItemClass) studio("models/pu_icon/coil/tris.md2") = item_coil : "Pickup item: coil ('Coil')." [] +@PointClass base(ItemClass) studio("models/pu_icon/f_light/tris.md2") = item_flashlight : "Pickup item: flashlight ('Flashlight')." [] +@PointClass base(ItemClass) studio("models/pu_icon/health/tris.md2") = item_health_lg: "Health: large medicine bag." [] +@PointClass base(ItemClass) studio("models/pu_icon/health_s/tris.md2") = item_health_sm: "Health: small medkit." [] +@PointClass base(ItemClass) studio("models/pu_icon/head/head.mdx") = item_lizzyhead : "Pickup item: Lizzy's head ('Lizzy Head')." [] +@PointClass base(ItemClass) studio("models/pu_icon/oilcan/tris.md2") = item_oilcan : "Pickup item: oil can ('Oil Can')." [] +@PointClass base(ItemClass) studio("models/pu_icon/backpack/tris.md2") = item_pack : "Pickup item: ammo pack ('Ammo Pack'), provides a few ammos for every weapon." [] +@PointClass base(ItemClass) studio("models/pu_icon/folder/tris.md2") = item_safedocs : "Pickup item: important documents ('Safe docs')." [] +@PointClass base(ItemClass) studio("models/pu_icon/valve/tris.md2") = item_valve : "Pickup item: valve ('Valve')." [] +@PointClass base(ItemClass) studio("models/pu_icon/watch/tris.md2") = item_watch : "Pickup item: Lenny's watch in Skidrow ('Watch')." [] +@PointClass base(ItemClass) studio("models/pu_icon/whiskey/tris.md2") = item_whiskey : "Pickup item: whiskey for the bum in Skidrow ('Whiskey')." [] + + +@baseclass base(Appearflags, Targetname, Target, Killtarget, Angle) size(-16 -16 -16, 16 16 16) color(0 128 204) = KeyClass [] +@PointClass base(KeyClass) studio("models/pu_icon/key/key_a.md2") = key_key1 : "Store_Room_Key, will allow player to unlock doors with a 'key' value of '1'" [] +@PointClass base(KeyClass) studio("models/pu_icon/key/key_b.md2") = key_key2 : "Electrical_Room, will allow player to unlock doors with a 'key' value of '2'" [] +@PointClass base(KeyClass) studio("models/pu_icon/key/key_c.md2") = key_key3 : "Chem_Plant_Key, will allow player to unlock doors with a 'key' value of '3'" [] +@PointClass base(KeyClass) studio("models/pu_icon/key/key_c.md2") = key_key4 : "Bridge_Key, will allow player to unlock doors with a 'key' value of '4'" [] +@PointClass base(KeyClass) studio("models/pu_icon/key/key_c.md2") = key_key5 : "Shipyard_Key, will allow player to unlock doors with a 'key' value of '5'" [] +@PointClass base(KeyClass) studio("models/pu_icon/key/key_c.md2") = key_key6 : "Warehouse_Key, will allow player to unlock doors with a 'key' value of '6'" [] +@PointClass base(KeyClass) studio("models/pu_icon/key/key_c.md2") = key_key7 : "Shop_Key, will allow player to unlock doors with a 'key' value of '7'" [] +@PointClass base(KeyClass) studio("models/pu_icon/key/key_c.md2") = key_key8 : "Ticket, will allow player to unlock doors with a 'key' value of '8'" [] +@PointClass base(KeyClass) studio("models/pu_icon/key/key_c.md2") = key_key9 : "Office_Key, will allow player to unlock doors with a 'key' value of '9'" [] +@PointClass base(KeyClass) studio("models/pu_icon/key/key_c.md2") = key_key10 : "Key10, will allow player to unlock doors with a 'key' value of '10'" [] +@PointClass size(-8 -8 -16, 8 8 16) color(0 128 204) studio("models/pu_icon/fuse/tris.md2") = key_fuse : "Pickup item: fuse ('Fuse')." +[ + spawnflags(flags) = + [ + 1 : "trigger_spawn" : 0 + 2 : "no_touch" : 0 + ] +] + + +@PointClass base(Appearflags, Target) color(0 255 0) size(-8 -8 -8, 8 8 8) = junior : "Used for dynamic lighting of characters and alias models." +[ + spawnflags(Flags) = + [ + 1 : "Start Off" : 0 + ] + light(integer) : "Brightness" : 300 + style(Choices) : "Style" : 0 = + [ + 0 : "Normal" + 1 : "Fire Flicker #1" + 2 : "Slow Strong Pulse" + 3 : "Candle #1" + 4 : "Fast Strobe" + 5 : "Gentle Pulse #1" + 6 : "Fire Flicker #2" + 7 : "Candle #2" + 8 : "Candle #3" + 9 : "Slow Strong Strobe" + 10 : "Fluorescent Flicker #1" + 11 : "Slow pulse, no black" + 12 : "Fire Flicker #3" + 13 : "Fluorescent Flicker #2" + 14 : "Fluorescent Flicker #3" + 15 : "Realistic Fade #1" + 16 : "Realistic Fade #2" + 17 : "Slow Strongstrobe (out of phase)" + 18 : "Three Cycle Strobe #1" + 19 : "Three Cycle Strobe #2" + 20 : "Three Cycle Strobe #3" + ] + _color(string) : "Defines the color in scalar R G B values" : "0 0 0" +] +@PointClass base(Appearflags, Target, Targetname) color(0 255 0) size(-8 -8 -8, 8 8 8) = light : "Light" +[ + spawnflags(Flags) = + [ + 1 : "Start Off" : 0 + 2 : "Flare" : 0 + 4 : "Noresize" : 0 + 8 : "Dynamic" : 0 + ] + light(integer) : "Brightness" : 300 + style(Choices) : "Style" : 0 = + [ + 0 : "Normal" + 1 : "Fire Flicker #1" + 2 : "Slow Strong Pulse" + 3 : "Candle #1" + 4 : "Fast Strobe" + 5 : "Gentle Pulse #1" + 6 : "Fire Flicker #2" + 7 : "Candle #2" + 8 : "Candle #3" + 9 : "Slow Strong Strobe" + 10 : "Fluorescent Flicker #1" + 11 : "Slow pulse, no black" + 12 : "Fire Flicker #3" + 13 : "Fluorescent Flicker #2" + 14 : "Fluorescent Flicker #3" + 15 : "Realistic Fade #1" + 16 : "Realistic Fade #2" + 17 : "Slow Strongstrobe (out of phase)" + 18 : "Three Cycle Strobe #1" + 19 : "Three Cycle Strobe #2" + 20 : "Three Cycle Strobe #3" + ] + dmg(Choices) : "Flare type" : 0 = + [ + 0 : "White" + 1 : "Sun" + 2 : "Amber" + 3 : "Red" + 4 : "Blue" + 5 : "Green" + ] + _cone(integer) : "Size of light (spotlight)" : 10 + _color(string) : "Defines the color in scalar R G B values" : "0 0 0" + movedir(string) : "Defines the color in scalar R G B values of the flare" + health(integer) : "Diameter of the flare" : 24 + _mangle(string) : "Yaw and pitch spot direction -- 0 to 360, -90 to 90, or you can use _spotvector" + _spotvector(string) : "Spot direction set by vector X Y Z, or you can use _spotpoint" + _spotpoint(string) : "Spot direction set by coordinate X Y Z." + _focus(float) : "Cone attenuation for spotlights" + _wait(integer) : "Light distance attenuation" + _angwait(float) : "Light angle attenuation" + _falloff(Choices) : "Fall off style" : 1 = + [ + 0 : "Linear" + 1 : "Inverse" + 2 : "Inverse Square" + ] +] +@PointClass base(Appearflags, Target, Targetname) color(255 255 255) size(-2 -2 -5, 2 2 5) studio("models\props\light\tris.md2") = light_bulb : "A bulb that outputs light." +[ + spawnflags(Flags) = + [ + 1 : "Start Off" : 0 + 2 : "Flare" : 0 + 4 : "Noresize" : 0 + 8 : "Dynamic" : 0 + ] + light(integer) : "Brightness" : 300 + style(Choices) : "Style" : 0 = + [ + 0 : "Normal" + 1 : "Fire Flicker #1" + 2 : "Slow Strong Pulse" + 3 : "Candle #1" + 4 : "Fast Strobe" + 5 : "Gentle Pulse #1" + 6 : "Fire Flicker #2" + 7 : "Candle #2" + 8 : "Candle #3" + 9 : "Slow Strong Strobe" + 10 : "Fluorescent Flicker #1" + 11 : "Slow pulse, no black" + 12 : "Fire Flicker #3" + 13 : "Fluorescent Flicker #2" + 14 : "Fluorescent Flicker #3" + 15 : "Realistic Fade #1" + 16 : "Realistic Fade #2" + 17 : "Slow Strongstrobe (out of phase)" + 18 : "Three Cycle Strobe #1" + 19 : "Three Cycle Strobe #2" + 20 : "Three Cycle Strobe #3" + ] + dmg(Choices) : "Flare type" : 0 = + [ + 0 : "White" + 1 : "Sun" + 2 : "Amber" + 3 : "Red" + 4 : "Blue" + 5 : "Green" + ] + _cone(integer) : "Size of light (spotlight)" : 10 + _color(string) : "Defines the color in scalar R G B values" : "0 0 0" + movedir(string) : "Defines the color in scalar R G B values of the flare" + health(integer) : "Diameter of the flare" : 24 + _mangle(string) : "Yaw and pitch spot direction -- 0 to 360, -90 to 90, or you can use _spotvector" + _spotvector(string) : "Spot direction set by vector X Y Z, or you can use _spotpoint" + _spotpoint(string) : "Spot direction set by coordinate X Y Z." + _focus(float) : "Cone attenuation for spotlights" + _wait(integer) : "Light distance attenuation" + _angwait(float) : "Light angle attenuation" + _falloff(Choices) : "Fall off style" : 1 = + [ + 0 : "Linear" + 1 : "Inverse" + 2 : "Inverse Square" + ] +] +@PointClass base(Appearflags, Target, Targetname, Angle) color(255 255 255) size(-36 -34 -32, 36 34 32) studio("models\props\chandelier\tris.md2") = light_chandelier : "A chandelier." +[ + spawnflags(Flags) = + [ + 1 : "Start Off" : 0 + 2 : "Flare" : 0 + 4 : "Noresize" : 0 + 8 : "Dynamic" : 0 + ] + light(integer) : "Brightness" : 300 + style(Choices) : "Style" : 0 = + [ + 0 : "Normal" + 1 : "Fire Flicker #1" + 2 : "Slow Strong Pulse" + 3 : "Candle #1" + 4 : "Fast Strobe" + 5 : "Gentle Pulse #1" + 6 : "Fire Flicker #2" + 7 : "Candle #2" + 8 : "Candle #3" + 9 : "Slow Strong Strobe" + 10 : "Fluorescent Flicker #1" + 11 : "Slow pulse, no black" + 12 : "Fire Flicker #3" + 13 : "Fluorescent Flicker #2" + 14 : "Fluorescent Flicker #3" + 15 : "Realistic Fade #1" + 16 : "Realistic Fade #2" + 17 : "Slow Strongstrobe (out of phase)" + 18 : "Three Cycle Strobe #1" + 19 : "Three Cycle Strobe #2" + 20 : "Three Cycle Strobe #3" + ] + dmg(Choices) : "Flare type" : 0 = + [ + 0 : "White" + 1 : "Sun" + 2 : "Amber" + 3 : "Red" + 4 : "Blue" + 5 : "Green" + ] + _cone(integer) : "Size of light (spotlight)" : 10 + _color(string) : "Defines the color in scalar R G B values" : "0 0 0" + movedir(string) : "Defines the color in scalar R G B values of the flare" + health(integer) : "Diameter of the flare" : 24 + _mangle(string) : "Yaw and pitch spot direction -- 0 to 360, -90 to 90, or you can use _spotvector" + _spotvector(string) : "Spot direction set by vector X Y Z, or you can use _spotpoint" + _spotpoint(string) : "Spot direction set by coordinate X Y Z." + _focus(float) : "Cone attenuation for spotlights" + _wait(integer) : "Light distance attenuation" + _angwait(float) : "Light angle attenuation" + _falloff(Choices) : "Fall off style" : 1 = + [ + 0 : "Linear" + 1 : "Inverse" + 2 : "Inverse Square" + ] +] +@PointClass base(Appearflags, Target, Targetname, Angle) color(255 255 255) size(-8 -8 -12, 8 8 12) studio("models\props\decosconce\tris.md2") = light_deco_sconce : "A deco sconce." +[ + spawnflags(Flags) = + [ + 1 : "Start Off" : 0 + 2 : "Flare" : 0 + 4 : "Noresize" : 0 + 8 : "Dynamic" : 0 + ] + light(integer) : "Brightness" : 300 + style(Choices) : "Style" : 0 = + [ + 0 : "Normal" + 1 : "Fire Flicker #1" + 2 : "Slow Strong Pulse" + 3 : "Candle #1" + 4 : "Fast Strobe" + 5 : "Gentle Pulse #1" + 6 : "Fire Flicker #2" + 7 : "Candle #2" + 8 : "Candle #3" + 9 : "Slow Strong Strobe" + 10 : "Fluorescent Flicker #1" + 11 : "Slow pulse, no black" + 12 : "Fire Flicker #3" + 13 : "Fluorescent Flicker #2" + 14 : "Fluorescent Flicker #3" + 15 : "Realistic Fade #1" + 16 : "Realistic Fade #2" + 17 : "Slow Strongstrobe (out of phase)" + 18 : "Three Cycle Strobe #1" + 19 : "Three Cycle Strobe #2" + 20 : "Three Cycle Strobe #3" + ] + dmg(Choices) : "Flare type" : 0 = + [ + 0 : "White" + 1 : "Sun" + 2 : "Amber" + 3 : "Red" + 4 : "Blue" + 5 : "Green" + ] + _cone(integer) : "Size of light (spotlight)" : 10 + _color(string) : "Defines the color in scalar R G B values" : "0 0 0" + movedir(string) : "Defines the color in scalar R G B values of the flare" + health(integer) : "Diameter of the flare" : 24 + _mangle(string) : "Yaw and pitch spot direction -- 0 to 360, -90 to 90, or you can use _spotvector" + _spotvector(string) : "Spot direction set by vector X Y Z, or you can use _spotpoint" + _spotpoint(string) : "Spot direction set by coordinate X Y Z." + _focus(float) : "Cone attenuation for spotlights" + _wait(integer) : "Light distance attenuation" + _angwait(float) : "Light angle attenuation" + _falloff(Choices) : "Fall off style" : 1 = + [ + 0 : "Linear" + 1 : "Inverse" + 2 : "Inverse Square" + ] +] +@PointClass base(Appearflags, Target, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = light_fire_esm : "Extra-small fire." +[ + spawnflags(Flags) = + [ + 8 : "Dynamic" : 0 + ] + alphalevel(integer) : "Opacity level -- 1 to 10" : 5 + light(integer) : "Brightness" : 300 + style(Choices) : "Style" : 0 = + [ + 0 : "Normal" + 1 : "Fire Flicker #1" + 2 : "Slow Strong Pulse" + 3 : "Candle #1" + 4 : "Fast Strobe" + 5 : "Gentle Pulse #1" + 6 : "Fire Flicker #2" + 7 : "Candle #2" + 8 : "Candle #3" + 9 : "Slow Strong Strobe" + 10 : "Fluorescent Flicker #1" + 11 : "Slow pulse, no black" + 12 : "Fire Flicker #3" + 13 : "Fluorescent Flicker #2" + 14 : "Fluorescent Flicker #3" + 15 : "Realistic Fade #1" + 16 : "Realistic Fade #2" + 17 : "Slow Strongstrobe (out of phase)" + 18 : "Three Cycle Strobe #1" + 19 : "Three Cycle Strobe #2" + 20 : "Three Cycle Strobe #3" + ] + dmg(Choices) : "Flare type" : 0 = + [ + 0 : "White" + 1 : "Sun" + 2 : "Amber" + 3 : "Red" + 4 : "Blue" + 5 : "Green" + ] + _cone(integer) : "Size of light (spotlight)" : 10 + _color(string) : "Defines the color in scalar R G B values" : "0 0 0" + movedir(string) : "Defines the color in scalar R G B values of the flare" + health(integer) : "Diameter of the flare" : 24 + _mangle(string) : "Yaw and pitch spot direction -- 0 to 360, -90 to 90, or you can use _spotvector" + _spotvector(string) : "Spot direction set by vector X Y Z, or you can use _spotpoint" + _spotpoint(string) : "Spot direction set by coordinate X Y Z." + _focus(float) : "Cone attenuation for spotlights" + _wait(integer) : "Light distance attenuation" + _angwait(float) : "Light angle attenuation" + _falloff(Choices) : "Fall off style" : 1 = + [ + 0 : "Linear" + 1 : "Inverse" + 2 : "Inverse Square" + ] +] +@PointClass base(Appearflags, Target, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = light_fire_lg : "Cool fire large." +[ + spawnflags(Flags) = + [ + 8 : "Dynamic" : 0 + ] + alphalevel(integer) : "Opacity level -- 1 to 10" : 5 + light(integer) : "Brightness" : 300 + style(Choices) : "Style" : 0 = + [ + 0 : "Normal" + 1 : "Fire Flicker #1" + 2 : "Slow Strong Pulse" + 3 : "Candle #1" + 4 : "Fast Strobe" + 5 : "Gentle Pulse #1" + 6 : "Fire Flicker #2" + 7 : "Candle #2" + 8 : "Candle #3" + 9 : "Slow Strong Strobe" + 10 : "Fluorescent Flicker #1" + 11 : "Slow pulse, no black" + 12 : "Fire Flicker #3" + 13 : "Fluorescent Flicker #2" + 14 : "Fluorescent Flicker #3" + 15 : "Realistic Fade #1" + 16 : "Realistic Fade #2" + 17 : "Slow Strongstrobe (out of phase)" + 18 : "Three Cycle Strobe #1" + 19 : "Three Cycle Strobe #2" + 20 : "Three Cycle Strobe #3" + ] + dmg(Choices) : "Flare type" : 0 = + [ + 0 : "White" + 1 : "Sun" + 2 : "Amber" + 3 : "Red" + 4 : "Blue" + 5 : "Green" + ] + _cone(integer) : "Size of light (spotlight)" : 10 + _color(string) : "Defines the color in scalar R G B values" : "0 0 0" + movedir(string) : "Defines the color in scalar R G B values of the flare" + health(integer) : "Diameter of the flare" : 24 + _mangle(string) : "Yaw and pitch spot direction -- 0 to 360, -90 to 90, or you can use _spotvector" + _spotvector(string) : "Spot direction set by vector X Y Z, or you can use _spotpoint" + _spotpoint(string) : "Spot direction set by coordinate X Y Z." + _focus(float) : "Cone attenuation for spotlights" + _wait(integer) : "Light distance attenuation" + _angwait(float) : "Light angle attenuation" + _falloff(Choices) : "Fall off style" : 1 = + [ + 0 : "Linear" + 1 : "Inverse" + 2 : "Inverse Square" + ] +] +@PointClass base(Appearflags, Target, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = light_fire_med : "Cool fire medium." +[ + spawnflags(Flags) = + [ + 8 : "Dynamic" : 0 + ] + alphalevel(integer) : "Opacity level -- 1 to 10" : 5 + light(integer) : "Brightness" : 300 + style(Choices) : "Style" : 0 = + [ + 0 : "Normal" + 1 : "Fire Flicker #1" + 2 : "Slow Strong Pulse" + 3 : "Candle #1" + 4 : "Fast Strobe" + 5 : "Gentle Pulse #1" + 6 : "Fire Flicker #2" + 7 : "Candle #2" + 8 : "Candle #3" + 9 : "Slow Strong Strobe" + 10 : "Fluorescent Flicker #1" + 11 : "Slow pulse, no black" + 12 : "Fire Flicker #3" + 13 : "Fluorescent Flicker #2" + 14 : "Fluorescent Flicker #3" + 15 : "Realistic Fade #1" + 16 : "Realistic Fade #2" + 17 : "Slow Strongstrobe (out of phase)" + 18 : "Three Cycle Strobe #1" + 19 : "Three Cycle Strobe #2" + 20 : "Three Cycle Strobe #3" + ] + dmg(Choices) : "Flare type" : 0 = + [ + 0 : "White" + 1 : "Sun" + 2 : "Amber" + 3 : "Red" + 4 : "Blue" + 5 : "Green" + ] + _cone(integer) : "Size of light (spotlight)" : 10 + _color(string) : "Defines the color in scalar R G B values" : "0 0 0" + movedir(string) : "Defines the color in scalar R G B values of the flare" + health(integer) : "Diameter of the flare" : 24 + _mangle(string) : "Yaw and pitch spot direction -- 0 to 360, -90 to 90, or you can use _spotvector" + _spotvector(string) : "Spot direction set by vector X Y Z, or you can use _spotpoint" + _spotpoint(string) : "Spot direction set by coordinate X Y Z." + _focus(float) : "Cone attenuation for spotlights" + _wait(integer) : "Light distance attenuation" + _angwait(float) : "Light angle attenuation" + _falloff(Choices) : "Fall off style" : 1 = + [ + 0 : "Linear" + 1 : "Inverse" + 2 : "Inverse Square" + ] +] +@PointClass base(Appearflags, Target, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = light_fire_sm : "Cool fire small." +[ + spawnflags(Flags) = + [ + 8 : "Dynamic" : 0 + ] + alphalevel(integer) : "Opacity level -- 1 to 10" : 5 + light(integer) : "Brightness" : 300 + style(Choices) : "Style" : 0 = + [ + 0 : "Normal" + 1 : "Fire Flicker #1" + 2 : "Slow Strong Pulse" + 3 : "Candle #1" + 4 : "Fast Strobe" + 5 : "Gentle Pulse #1" + 6 : "Fire Flicker #2" + 7 : "Candle #2" + 8 : "Candle #3" + 9 : "Slow Strong Strobe" + 10 : "Fluorescent Flicker #1" + 11 : "Slow pulse, no black" + 12 : "Fire Flicker #3" + 13 : "Fluorescent Flicker #2" + 14 : "Fluorescent Flicker #3" + 15 : "Realistic Fade #1" + 16 : "Realistic Fade #2" + 17 : "Slow Strongstrobe (out of phase)" + 18 : "Three Cycle Strobe #1" + 19 : "Three Cycle Strobe #2" + 20 : "Three Cycle Strobe #3" + ] + dmg(Choices) : "Flare type" : 0 = + [ + 0 : "White" + 1 : "Sun" + 2 : "Amber" + 3 : "Red" + 4 : "Blue" + 5 : "Green" + ] + _cone(integer) : "Size of light (spotlight)" : 10 + _color(string) : "Defines the color in scalar R G B values" : "0 0 0" + movedir(string) : "Defines the color in scalar R G B values of the flare" + health(integer) : "Diameter of the flare" : 24 + _mangle(string) : "Yaw and pitch spot direction -- 0 to 360, -90 to 90, or you can use _spotvector" + _spotvector(string) : "Spot direction set by vector X Y Z, or you can use _spotpoint" + _spotpoint(string) : "Spot direction set by coordinate X Y Z." + _focus(float) : "Cone attenuation for spotlights" + _wait(integer) : "Light distance attenuation" + _angwait(float) : "Light angle attenuation" + _falloff(Choices) : "Fall off style" : 1 = + [ + 0 : "Linear" + 1 : "Inverse" + 2 : "Inverse Square" + ] +] +@PointClass base(Appearflags, Target, Targetname, Angle) color(255 255 255) size(-16 -16 -4, 16 16 4) studio("models\props\pendant\tris.md2") = light_pendant : "A pendant light." +[ + spawnflags(Flags) = + [ + 1 : "Start Off" : 0 + 2 : "Flare" : 0 + 4 : "Noresize" : 0 + 8 : "Dynamic" : 0 + ] + light(integer) : "Brightness" : 300 + style(Choices) : "Style" : 0 = + [ + 0 : "Normal" + 1 : "Fire Flicker #1" + 2 : "Slow Strong Pulse" + 3 : "Candle #1" + 4 : "Fast Strobe" + 5 : "Gentle Pulse #1" + 6 : "Fire Flicker #2" + 7 : "Candle #2" + 8 : "Candle #3" + 9 : "Slow Strong Strobe" + 10 : "Fluorescent Flicker #1" + 11 : "Slow pulse, no black" + 12 : "Fire Flicker #3" + 13 : "Fluorescent Flicker #2" + 14 : "Fluorescent Flicker #3" + 15 : "Realistic Fade #1" + 16 : "Realistic Fade #2" + 17 : "Slow Strongstrobe (out of phase)" + 18 : "Three Cycle Strobe #1" + 19 : "Three Cycle Strobe #2" + 20 : "Three Cycle Strobe #3" + ] + dmg(Choices) : "Flare type" : 0 = + [ + 0 : "White" + 1 : "Sun" + 2 : "Amber" + 3 : "Red" + 4 : "Blue" + 5 : "Green" + ] + _cone(integer) : "Size of light (spotlight)" : 10 + _color(string) : "Defines the color in scalar R G B values" : "0 0 0" + movedir(string) : "Defines the color in scalar R G B values of the flare" + health(integer) : "Diameter of the flare" : 24 + _mangle(string) : "Yaw and pitch spot direction -- 0 to 360, -90 to 90, or you can use _spotvector" + _spotvector(string) : "Spot direction set by vector X Y Z, or you can use _spotpoint" + _spotpoint(string) : "Spot direction set by coordinate X Y Z." + _focus(float) : "Cone attenuation for spotlights" + _wait(integer) : "Light distance attenuation" + _angwait(float) : "Light angle attenuation" + _falloff(Choices) : "Fall off style" : 1 = + [ + 0 : "Linear" + 1 : "Inverse" + 2 : "Inverse Square" + ] +] +@PointClass base(Appearflags, Target, Targetname, Angle) color(255 255 255) size(-4 -4 -8, 4 4 8) + model( + {{ + spawnflags & 128 -> "models/props/sconce/lighty.md2", + spawnflags & 64 -> "models/props/sconce/lightr.md2", + spawnflags & 32 -> "models/props/sconce/lightg.md2", + spawnflags & 16 -> "models/props/sconce/lightb.md2", + "models/props/sconce/light.md2" + }} + ) = light_sconce : "A cage light model, set correct skin with spawnflags." +[ + spawnflags(Flags) = + [ + 1 : "Start off" : 0 + 2 : "Flare" : 0 + 4 : "Noresize" : 0 + 8 : "Dynamic" : 0 + 16 : "Blue model" : 0 + 32 : "Green model" : 0 + 64 : "Red model" : 0 + 128 : "Yellow model" : 0 + ] + light(integer) : "Brightness" : 300 + style(Choices) : "Style" : 0 = + [ + 0 : "Normal" + 1 : "Fire Flicker #1" + 2 : "Slow Strong Pulse" + 3 : "Candle #1" + 4 : "Fast Strobe" + 5 : "Gentle Pulse #1" + 6 : "Fire Flicker #2" + 7 : "Candle #2" + 8 : "Candle #3" + 9 : "Slow Strong Strobe" + 10 : "Fluorescent Flicker #1" + 11 : "Slow pulse, no black" + 12 : "Fire Flicker #3" + 13 : "Fluorescent Flicker #2" + 14 : "Fluorescent Flicker #3" + 15 : "Realistic Fade #1" + 16 : "Realistic Fade #2" + 17 : "Slow Strongstrobe (out of phase)" + 18 : "Three Cycle Strobe #1" + 19 : "Three Cycle Strobe #2" + 20 : "Three Cycle Strobe #3" + ] + dmg(Choices) : "Flare type" : 0 = + [ + 0 : "White" + 1 : "Sun" + 2 : "Amber" + 3 : "Red" + 4 : "Blue" + 5 : "Green" + ] + _cone(integer) : "Size of light (spotlight)" : 10 + _color(string) : "Defines the color in scalar R G B values" : "0 0 0" + movedir(string) : "Defines the color in scalar R G B values of the flare" + health(integer) : "Diameter of the flare" : 24 + _mangle(string) : "Yaw and pitch spot direction -- 0 to 360, -90 to 90, or you can use _spotvector" + _spotvector(string) : "Spot direction set by vector X Y Z, or you can use _spotpoint" + _spotpoint(string) : "Spot direction set by coordinate X Y Z." + _focus(float) : "Cone attenuation for spotlights" + _wait(integer) : "Light distance attenuation" + _angwait(float) : "Light angle attenuation" + _falloff(Choices) : "Fall off style" : 1 = + [ + 0 : "Linear" + 1 : "Inverse" + 2 : "Inverse Square" + ] +] +@PointClass size(-16 -16 -16, 16 16 16) color(0 0 255) = sfx_beacon : "Some rotating beam."[] +@PointClass base(Appearflags, Target, Targetname) color(0 255 0) size(-2 -2 -2, 2 2 2) = lightflare : "Non-displayed light." +[ + spawnflags(Flags) = + [ + 1 : "Start Off" : 0 + 2 : "Flare" : 0 + 4 : "Noresize" : 0 + 8 : "Dynamic" : 0 + ] + light(integer) : "Brightness" : 300 + style(Choices) : "Style" : 0 = + [ + 0 : "Normal" + 1 : "Fire Flicker #1" + 2 : "Slow Strong Pulse" + 3 : "Candle #1" + 4 : "Fast Strobe" + 5 : "Gentle Pulse #1" + 6 : "Fire Flicker #2" + 7 : "Candle #2" + 8 : "Candle #3" + 9 : "Slow Strong Strobe" + 10 : "Fluorescent Flicker #1" + 11 : "Slow pulse, no black" + 12 : "Fire Flicker #3" + 13 : "Fluorescent Flicker #2" + 14 : "Fluorescent Flicker #3" + 15 : "Realistic Fade #1" + 16 : "Realistic Fade #2" + 17 : "Slow Strongstrobe (out of phase)" + 18 : "Three Cycle Strobe #1" + 19 : "Three Cycle Strobe #2" + 20 : "Three Cycle Strobe #3" + ] + dmg(Choices) : "Flare type" : 0 = + [ + 0 : "White" + 1 : "Sun" + 2 : "Amber" + 3 : "Red" + 4 : "Blue" + 5 : "Green" + ] + _cone(integer) : "Size of light (spotlight)" : 10 + _color(string) : "Defines the color in scalar R G B values" : "0 0 0" + movedir(string) : "Defines the color in scalar R G B values of the flare" + health(integer) : "Diameter of the flare" : 24 + _mangle(string) : "Yaw and pitch spot direction -- 0 to 360, -90 to 90, or you can use _spotvector" + _spotvector(string) : "Spot direction set by vector X Y Z, or you can use _spotpoint" + _spotpoint(string) : "Spot direction set by coordinate X Y Z." + _focus(float) : "Cone attenuation for spotlights" + _wait(integer) : "Light distance attenuation" + _angwait(float) : "Light angle attenuation" + _falloff(Choices) : "Fall off style" : 1 = + [ + 0 : "Linear" + 1 : "Inverse" + 2 : "Inverse Square" + ] +] + + + +@PointClass base(Appearflags, Targetname) size(-8 -8 -8, 8 8 8) color(255 128 0) = misc_alarm : "Rings when triggered, when turned on, triggers the 'alarm' eventscript." +[ + speed(integer) : "Wait time before alarmed" : 3 + count(integer) : "Duration of alarm ringing" : 60 +] +@PointClass base(Appearflags, Target, Targetname) size(-16 -16 -16, 16 16 16) color(0 0 255) = misc_cutscene_camera : "Camera, must be triggered by a 'misc_cutscene_trigger' or 'misc_use_cutscene', relay from 'misc_cutscene_camera' to 'misc_cutscene_camera' using 'target', cutscene will end when there's no more camera." +[ + cameraorigin(string) : "X Y Z camera start position (overrides entity's origin)" + cameraangle(string) : "X Y Z start angles" + rotate(string) : "X Y Z rotational velocity during cut scene" + target2(string) : "Always look at that entity (overrides angles when moving)" + cameravel(string) : "[forward] [right] [up] speed to move from initial angle" + cameravelrel(string) : "[forward] [right] [up] speed to move relative to current frame angle" + wait(integer) : "Time before switching to next camera in seconds" : 5 + accel(float) : "Acceleration rate when starting to move" + decel(float) : "Deceleration rate when approaching the end of use" + delay(integer) : "Delay before starting to move ('decel' and 'accel' must be set)" + reactdelay(integer) : "Moving time ('accel' must be set, if there's no 'decel', will never stop moving)" + duration(integer) : "Fade out time" + name(sound) : "Sound to play once triggered" + sight_target(string) : "Talking actor (if there's a sound to play)" + deadticks(integer) : "Fov for this camera" : 90 + scriptname(string) : "Script name to trigger when starting the camera" +] +@PointClass base(Appearflags, Target) = misc_cutscene_trigger : "This entity tells the code to unlink the camera from the client, so we can move it around. Once triggered, this entity should trigger a 'misc_cutscene_camera'." +[ + debugprint(integer) : "when set to 1, will print out camera end position and angles" + duration(float) : "fade in time in seconds" +] +@PointClass base(Appearflags, Target) size(-8 -8 -8, 8 8 8) color(128 128 128) = misc_use_cutscene : "This entity tells the code to unlink the camera from the client, so we can move it around. Once triggered, this entity should trigger a 'misc_cutscene_camera'." +[ + debugprint(integer) : "when set to 1, will print out camera end position and angles" + duration(float) : "fade in time in seconds" +] + + + +@PointClass size(-16 -16 -24, 16 16 48) color(102 77 204) = path_attractor : "When this is placed on the map it will attract actors by name from the episode ai routines" +[ + delay(integer) : "number of seconds before attract ai" : 10 +] +@PointClass base(Appearflags, Target, Targetname, Killtarget) size(-8 -8 -8, 8 8 8) color(128 77 0) = path_corner : "It defines a destination point for moving brush entities. Use path_corner_cast for AI's paths." +[ + spawnflags(flags) = + [ + 1 : "teleport" : 0 + ] + pathtarget(string) : "Entity to trigger when an entity that has this path_corner targeted touches it" + wait(integer) : "Wait (in seconds)" + speed(integer) : "Func_train_rotating only: departure speed from that corner" + rotate(string) : "Func_train_rotating only: angle change for X Y Z to next corner" + duration(string) : "Func_train_rotating only: duration for angle change (overrides speed)" + +] +@PointClass base(Appearflags, Target, Targetname, Killtarget) size(-16 -16 -24, 16 16 42) color(128 77 0) = path_corner_cast : "It defines a destination point for moving actors, when an actor reach the point, an event can be triggered. Use path_corner for brush-based entities." +[ + spawnflags(flags) = + [ + 1 : "teleport" : 0 + ] + pathtarget(string) : "Entity to trigger when an entity that has this path_corner targeted touches it" + wait(integer) : "Wait (in seconds)" + combattarget(string) : "When the cast reaches this marker, they'll attack this target" + name(sound) : "Sound to play when reached." + scriptname(string) : "Hard-coded script to call when reaching this marker" +] + + +@PointClass base(Angle) size(-64 -8 -36, 64 8 28) color(255 128 0) studio("models/props/menu_mdx/frame.mdx") = pawn_o_matic : "Two-sided panels used to select stuff in any pawn-o-matic." +[ + count(choices) : "Used to check what pawn-o-matic we're in. 1 or 2, 2 got more items to buy. But only works on episode skidrow (default=1)" : 1 = + [ + 1 : "Less Items" + 2 : "More Items" + ] +] + +@baseclass base(Appearflags, Targetname, Target, Killtarget, Angle) size(-16 -16 -16, 16 16 16) color(179 77 102) = PistolClass [] +@PointClass base(PistolClass ) studio("models/pu_icon/magmod/tris.md2") = pistol_mod_damage : "Magnum mod for the pistol (weapon_pistol, weapon_spistol), increases damages." [] +@PointClass base(PistolClass ) studio("models/pu_icon/reload_mod/tris.md2") = pistol_mod_reload : "Reload mod for the pistol (weapon_pistol, weapon_spistol), increases the reload speed." [] +@PointClass base(PistolClass ) studio("models/pu_icon/ro_fire_mod/tris.md2") = pistol_mod_rof : "Rate of fire mod for the pistol (weapon_pistol, weapon_spistol), increases rate of fire." [] + + + +@PointClass base(Appearflags, Angle) size(-16 -16 -24, 16 16 24) color(0 128 204) studio("models\props\aircon\tris.md2") = props_aircon : "A cool box deluxe." [] +@PointClass base(Appearflags, Angle) size(-32 -16 -8, 32 16 8) color(0 128 204) studio("models\props\crate\tris.md2") = props_ammocrate_bust : "An ammo crate you may bust with a melee weapon (crowbar or pipe) to get its content, will explose if broken otherwise, the bounding box can be rotated in angles of 90 deg and block properly." +[ + mass(integer) : "Weigth" : 400 + health(integer) : "Strength" : 10 + dmg(integer) : "Damages to inflic on destruction" : 0 + item(string) : "Item to spawn on destruction" +] +@PointClass base(Appearflags, Angle) size(-28 -22 -22, 28 22 22) color(0 128 204) studio("models\props\antenna\antenna.mdx") = props_antenna1a : "An antenna." [] +@PointClass base(Appearflags, Angle) size(-41 -33 -32, 41 33 32) color(0 128 204) studio("models\props\ant1b\antenna.mdx") = props_antenna1b : "An antenna." [] +@PointClass base(Appearflags, Angle) size(-55 -44 -43, 55 44 43) color(0 128 204) studio("models\props\ant1c\antenna.mdx") = props_antenna1c : "An antenna." [] +@PointClass base(Appearflags, Angle) size(-26 -30 -22, 26 30 22) color(0 128 204) studio("models\props\ant2a\antenna.mdx") = props_antenna2a : "An antenna." [] +@PointClass base(Appearflags, Angle) size(-38 -45 -32, 38 45 32) color(0 128 204) studio("models\props\ant2b\antenna.mdx") = props_antenna2b : "An antenna." [] +@PointClass base(Appearflags, Angle) size(-50 -60 -43, 60 50 43) color(0 128 204) studio("models\props\ant2c\antenna.mdx") = props_antenna2c : "An antenna." [] +@PointClass base(Appearflags, Angle) size(-14 -2 -22, 14 2 22) color(0 128 204) studio("models\props\ant3a\antenna.mdx") = props_antenna3a : "An antenna." [] +@PointClass base(Appearflags, Angle) size(-21 -3 -33, 21 3 33) color(0 128 204) studio("models\props\ant3b\antenna.mdx") = props_antenna3b : "An antenna." [] +@PointClass base(Appearflags, Angle) size(-28 -3 -44, 28 3 44) color(0 128 204) studio("models\props\ant3c\antenna.mdx") = props_antenna3c : "An antenna." [] +@PointClass base(Appearflags, Targetname, Target, Angle) size(-140 -40 -58, 140 40 58) color(0 128 204) studio("models\props\blimp\tris.md2") = props_blimp : "A moving blimp, trigger to make visible and start moving." +[ + speed(integer) : "Movement speed" : 20 +] +@PointClass base(Appearflags, Angle) size(-11 -13 -26, 11 13 26) color(0 128 204) studio("models\props\chair\chair.mdx") = props_chair : "A chair\n\nskin=models\props\chair\chair1.tga" [] +@PointClass base(Appearflags, Angle) size(-16 -24 -32, 16 24 32) color(0 128 204) studio("models\props\cigmachine\tris.md2") = props_cig_machine : "A cigarette machine, bounding box can be rotated in angles of 90 deg and block properly." [] +@PointClass base(Appearflags, Angle) size(-16 -24 -32, 24 32 32) color(0 128 204) studio("models\props\vending_mach\tris.md2") = props_cola_machine : "A cola machine, bounding box can be rotated in angles of 90 deg and block properly." [] +@PointClass base(Appearflags, Angle) size(-16 -16 -16, 16 16 16) color(0 128 204) studio("models\props\crate\stillcrate32_1.mdx") = props_crate_bust_32 : "Crate can bust and you can push." +[ + mass(integer) : "Weigth" : 400 + health(integer) : "Strength" : 10 + dmg(integer) : "Damages to inflic on destruction" : 0 + item(string) : "Item to spawn on destruction" + spawnflags(flags) = + [ + 2 : "Non Moveable" : 0 + 4 : "Wood" : 0 + 8 : "Wood 2" : 0 + 16 : "Metal" : 0 + 32 : "Cardboard" : 0 + ] +] +@PointClass base(Appearflags, Angle) size(-24 -24 -24, 24 24 24) color(0 128 204) studio("models\props\crate\stillcrate48_1.mdx") = props_crate_bust_48 : "Crate can bust and you can push." +[ + mass(integer) : "Weigth" : 400 + health(integer) : "Strength" : 10 + dmg(integer) : "Damages to inflic on destruction" : 0 + item(string) : "Item to spawn on destruction" + spawnflags(flags) = + [ + 2 : "Non Moveable" : 0 + 4 : "Wood" : 0 + 8 : "Wood 2" : 0 + 16 : "Metal" : 0 + 32 : "Cardboard" : 0 + ] +] +@PointClass base(Appearflags, Angle) size(-32 -32 -32, 32 32 32) color(0 128 204) studio("models\props\crate\stillcrate64_1.mdx") = props_crate_bust_64 : "Pushable crate can bust." +[ + mass(integer) : "Weigth" : 400 + health(integer) : "Strength" : 10 + dmg(integer) : "Damages to inflic on destruction" : 0 + item(string) : "Item to spawn on destruction" + spawnflags(flags) = + [ + 4 : "Wood" : 0 + 8 : "Wood 2" : 0 + 16 : "Metal" : 0 + 32 : "Cardboard" : 0 + ] +] +@PointClass base(Appearflags, Angle) size(-16 -16 -16, 16 16 16) color(0 128 204) studio("models\pu_icon\exting\ext1.md2") = props_extinguisherA : "A breakable extinguisher." +[ + dmg(integer) : "Damages to inflic on destruction" : 25 +] +@PointClass base(Appearflags, Angle) size(-16 -16 -16, 16 16 16) color(0 128 204) studio("models\pu_icon\exting\ext2.md2") = props_extinguisherB : "A breakable extinguisher." +[ + dmg(integer) : "Damages to inflic on destruction" : 25 +] +@PointClass base(Appearflags, Angle) size(-8 -12 -16, 8 12 16) color(0 128 204) studio("models\props\fan\tris.md2") = props_fan : "A fan." [] +@PointClass base(Appearflags, Angle) size(-10 -10 -19, 10 10 19) color(0 128 204) studio("models\props\hydrant\tris.md2") = props_hydrant : "A hydrant that does jack." [] +@PointClass base(Appearflags, Angle) size(-36 -28 -38, 36 28 38) color(0 128 204) studio("models/props/mattress/matt.md2") = props_mattressA : "A mattress." [] +@PointClass base(Appearflags, Angle) size(-8 -34 -38, 8 34 38) color(0 128 204) studio("models/props/mattress/matt2.md2") = props_mattressB : "A mattress." [] +@PointClass base(Appearflags, Angle) size(-34 -38 -8, 34 38 8) color(0 128 204) studio("models/props/mattress/matt3.md2") = props_mattressC : "A mattress." [] +@PointClass base(Appearflags, Angle) size(-60 -20 -26, 60 20 26) color(0 128 204) studio("models\props\moto\moto.mdx;models\props\moto\chrome.mdx") = props_motorcycle : "A motorcycle." [] +@PointClass base(Appearflags) size(-16 -16 -16, 16 16 16) color(0 128 204) studio("models/props/ride/head.mdx;models/props/ride/moto.mdx;models/props/ride/body.mdx;models/props/ride/legs.mdx;models/props/ride/cigar.mdx") = props_motorcycle_run : "A motorcycle speeding away." [] +@PointClass base(Appearflags) size(-16 -16 -16, 16 16 16) color(0 128 204) studio("models/props/runaway/head.mdx;models/props/runaway/moto.mdx;models/props/runaway/body.mdx;models/props/runaway/legs.mdx") = props_motorcycle_runaway : "A motorcycle riding in place." [] +@PointClass base(Appearflags, Angle) size(-8 -8 -6, 8 8 6) color(0 128 204) studio("models\props\phone\tris.md2") = props_phone : "A phone (telephone)." [] +@PointClass base(Appearflags, Angle) size(-8 -12 -8, 8 12 8) color(0 128 204) studio("models\props\radio\tris.md2") = props_radio : "A radio that will take damage and activate triggers on destruction." +[ + health(integer) : "Strength, unbreakable if 666" : 25 +] +@PointClass base(Appearflags, Angle) size(-12 -12 0, 12 12 10) color(0 128 204) studio("models/actors/rat/rat.mdx") = props_rat : "A rat." +[ + option(integer) : "Set to '1' to make them dissapear if cvar props == 0" + health(integer) : "Rat health" : 10 + dmg(integer) : "Rat bite damage" : 2 +] +@PointClass base(Appearflags, Targetname, Angle) size(-16 -16 -16, 16 16 16) color(0 128 204) = props_rat_spawner : "Base rat spawner, props_rat_spawner_node determine possible spawn point" +[ + option(integer) : "Set to '1' to make them dissapear if cvar props == 0" + health(integer) : "Rat health" : 10 + dmg(integer) : "Rat bite damage" : 2 + deadticks(integer) : "Total number of rats in level from spawner at a time" : 5 +] +@PointClass base(Appearflags, Targetname, Angle) size(-16 -16 -16, 16 16 16) color(0 128 204) = props_rat_spawner_node : "Possible rat spawn point for 'props_rat_spawner'" [] +@PointClass base(Appearflags, Targetname, Angle) size(-12 -12 0, 12 12 10) color(0 128 204) studio("models/actors/rat/rat.mdx") = props_rat_trigger : "A rat that is spawned when triggered." +[ + option(integer) : "Set to '1' to make them dissapear if cvar props == 0" + health(integer) : "Rat health" : 10 + dmg(integer) : "Rat bite damage" : 2 +] +@PointClass base(Appearflags, Angle) size(-32 -36 -48, 32 36 48) color(0 128 204) studio("models\props\roof_vent\tris.md2") = props_roof_vent : "A breakable moving roof vent." +[ + health(integer) : "Strength" : 25 +] +@PointClass base(Appearflags, Angle) size(-40 -85 -51, 40 85 51) color(0 128 204) studio("models\props\shelf\flametank.mdx;models\props\shelf\pistol.mdx;models\props\shelf\shotgun.mdx;models\props\shelf\sshell.mdx;models\props\shelf\tomgun.mdx") = props_shelf : "The pawn shop shelf." [] +@PointClass base(Appearflags, Angle) size(-8 -8 -8, 8 8 8) color(0 128 204) = props_steam_machine : "A real steam producer, always on, no model" +[ + alphalevel(integer) : "Opacity level, 1 to 10" : 2 + firetype(integer) : "Length of steam, 1 to 100": 15 + thudsurf(integer) : "Start size of steam, 1 to 10 " : 5 + thudsnd(integer) : "End size steam increase, 1 to 10" : 5 + deadticks(integer) : "Number of steam puffs per length element, 1 to 10" : 2 +] +@PointClass base(Appearflags, Angle) size(-26 -27 -6, 26 27 6) color(0 128 204) studio("models\props\tablesets\set.mdx") = props_tablesetA : "Card-shark table setting." [] +@PointClass base(Appearflags, Angle) size(-64 -64 -4, 64 64 4) color(0 128 204) studio("models\props\trash\tris.md2") = props_trash : "Some trash." [] +@PointClass base(Appearflags, Angle) size(-8 -2 -2, 8 2 2) color(0 128 204) studio("models\props\trashbottle\tris.md2") = props_trashbottle : "Some trash." [] +@PointClass base(Appearflags, Angle) size(-2 -2 -8, 2 2 8) color(0 128 204) studio("models\props\trashbottle_vert\tris.md2") = props_trashbottle_vert : "A vertical trash bottle." [] +@PointClass base(Appearflags, Angle) size(-16 -16 -21, 16 16 21) color(0 128 204) studio("models/props/t_can2/tris.md2") = props_trashcan_fall : "Trash can you can push." +[ + mass(integer) : "Weigth" : 400 + health(integer) : "Strength" : 10 + dmg(integer) : "Damages to inflic on destruction" : 0 + item(string) : "Item to spawn on destruction" +] +@PointClass base(Appearflags, Angle) size(-16 -16 -21, 16 16 21) color(0 128 204) studio("models/props/t_can/tris.md2") = props_trashcanA : "A trash can you can push." +[ + spawnflags(Flags) = + [ + 2 : "Non Moveable" : 0 + ] + mass(integer) : "Weigth" : 400 + health(integer) : "Strength" : 10 + dmg(integer) : "Damages to inflic on destruction" : 0 + item(string) : "Item to spawn on destruction" +] +@PointClass base(Appearflags, Angle) size(-40 -40 -8, 40 40 8) color(0 128 204) studio("models\props\trashcorner\tris.md2") = props_trashcorner : "Some trash." [] +@PointClass base(Appearflags, Angle) size(-18 -18 -2, 18 18 2) color(0 128 204) studio("models\props\trashpaper\tris.md2") = props_trashpaper : "Some trash." [] +@PointClass base(Appearflags, Angle) size(-70 -25 -10, 70 25 10) color(0 128 204) studio("models\props\trashwall\tris.md2") = props_trashwall : "Some trash." [] +@PointClass base(Appearflags, Angle) size(-8 -16 -22, 8 16 22) color(0 128 204) studio("models\props\tv\tv.md2") = props_tv : "A television." [] +@PointClass base(Appearflags, Targetname, Angle) size(-64 -26 -48, 64 26 48) color(0 128 204) studio("models\props\wall\wall.mdx") = props_wall_fall : "A wall that falls when trigered." [] + + + + +@PointClass base(Appearflags, Angle) size(-12 -18 -4, 12 18 4) color(0 128 204) studio("models\props\ashtray_set\tris.md2") = props2_ashtray : "An ashtray." [] +@PointClass base(Appearflags, Targetname, Angle) size(-89 -48 -56, 89 48 56) color(0 128 204) studio("models\props\barl_steel\barrels.mdx;models\props\barl_steel\door.mdx;models\props\barl_steel\tops.mdx") = props2_barrels_fall_ST : "A set of barrels that you can trigger to fall." [] +@PointClass base(Appearflags, Targetname, Angle) size(-69 -33 -49, 69 33 49) color(0 128 204) studio("models\props\barl1\barrels.mdx;models\props\barl1\tops.mdx") = props2_barrels_fallA : "A set of barrels that you can trigger to fall." [] +@PointClass base(Appearflags, Targetname, Angle) size(-33 -81 -49, 33 81 49) color(0 128 204) studio("models\props\barl2\barrels2.mdx;models\props\barl2\tops2.mdx") = props2_barrels_fallB : "Another set of barrels that you can trigger to fall." [] +@PointClass base(Appearflags, Targetname, Angle) size(-90 -32 -48, 90 32 48) color(0 128 204) studio("models/props/pv_barl1/top_barrel_v4.mdx;models/props/pv_barl1/barrel_v2.mdx;models/props/pv_barl1/barrel_v4.mdx;models/props/pv_barl1/top_barrel_v2.mdx") = props2_barrels_PV_A : "A set of barrels that you can trigger to fall." [] +@PointClass base(Appearflags, Targetname, Angle) size(-17 -77 -49, 17 77 49) color(0 128 204) studio("models/props/pv_barl7/top_barrel_v4.mdx;models/props/pv_barl7/barrel_v2.mdx;models/props/pv_barl7/barrel_v4.mdx;models/props/pv_barl7/top_barrel_v2.mdx") = props2_barrels_PV_B : "A set of barrels that you can trigger to fall." [] +@PointClass base(Appearflags, Targetname, Angle) size(-68 -50 -48, 68 50 48) color(0 128 204) studio("models/props/pv_barl3/top_barrel_v4.mdx;models/props/pv_barl3/barrel_v2.mdx;models/props/pv_barl3/barrel_v4.mdx;models/props/pv_barl3/top_barrel_v2.mdx") = props2_barrels_PV_C : "A set of barrels that you can trigger to fall." [] +@PointClass base(Appearflags, Targetname, Angle) size(-20 -52 -48, 20 52 48) color(0 128 204) studio("models/props/pv_barl4/top_barrel_v4.mdx;models/props/pv_barl4/barrel_v2.mdx;models/props/pv_barl4/barrel_v4.mdx;models/props/pv_barl4/top_barrel_v2.mdx") = props2_barrels_PV_D : "A set of barrels that you can trigger to fall." [] +@PointClass base(Appearflags, Targetname, Angle) size(-24 -64 -48, 24 64 48) color(0 128 204) studio("models/props/pv_barl5/barrel_v4.mdx;models/props/pv_barl5/barrel_v2.mdx;models/props/pv_barl5/top_barrel_v4.mdx;models/props/pv_barl5/top_barrel_v2.mdx") = props2_barrels_PV_E : "A set of barrels that you can trigger to fall." [] +@PointClass base(Appearflags, Targetname, Angle) size(-20 -32 -24, 20 32 24) color(0 128 204) studio("models/props/pv_barl5/top_barrel_v4.mdx;models/props/pv_barl5/barrel_v2.mdx;models/props/pv_barl5/barrel_v4.mdx;models/props/pv_barl5/top_barrel_v2.mdx") = props2_barrels_PV_F : "A set of barrels that you can trigger to fall." [] +@PointClass base(Appearflags, Angle) size(-80 -160 -38, 80 160 38) color(0 128 204) studio("models\props\boat\boat.mdx;models\props\boat\glass.mdx") = props2_boat : "A boat, the bounding box can be rotated in angles of 90 deg and block properly." [] +@PointClass base(Appearflags, Angle) size(-80 -160 -38, 80 160 38) color(0 128 204) studio("models\props\boata\boat.mdx;models\props\boata\window.mdx") = props2_boat_animate : "An animated boat." [] +@PointClass base(Appearflags, Angle) size(-5 -9 -12, 5 9 12) color(0 128 204) studio("models\props\boatphone\tris.md2") = props2_boatphone : "A boat phone." [] +@PointClass base(Appearflags, Angle) size(-41 -41 -75, 41 41 75) color(0 128 204) studio("models\props\buoy\buoy.mdx;models\props\buoy\light.mdx") = props2_buoy : "A buoy" [] +@PointClass base(Appearflags, Angle) size(-41 -41 -75, 41 41 75) color(0 128 204) studio("models\props\buoya\buoy.mdx;models\props\buoya\light.mdx") = props2_buoy_animate : "An animated buoy." [] +@PointClass base(Appearflags, Angle) size(-81 -55 -64, 81 55 64) color(255 0 0) studio("models\props\buoyside\buoy.mdx;models\props\buoyside\light.mdx") = props2_buoy_side : "A buoy on it's side." [] +@PointClass base(Appearflags, Targetname) size(-16 -16 -16, 16 16 16) color(0 128 204) studio("models/props/cars/car.mdx;models/props/cars/legs_boss.mdx;models/props/cars/body_boss.mdx;models/props/cars/head_boss.mdx;models/props/cars/legs_chick.mdx;models/props/cars/body_chick.mdx;models/props/cars/head_chick.mdx") = props2_car_animate : "A car and actors (Blunt & Nikki Blanco) that animate when trigered." [] +@PointClass base(Appearflags, Angle) size(-50 -102 -33, 50 102 33) color(0 128 204) studio("models\props\car\car_td.md2") = props2_car_topdown : "A car with top down, the bounding box can be rotated in angles of 90 deg and block properly." [] +@PointClass base(Appearflags, Angle) size(-50 -102 -35, 50 102 35) color(0 128 204) studio("models\props\car\car_up.md2") = props2_car_topup : "A car with top up, the bounding box can be rotated in angles of 90 deg and block properly." [] +@PointClass base(Appearflags, Angle) size(-24 -24 -32, 24 24 32) color(0 128 204) studio("models/props/confchair/tris.md2") = props2_chair_conf : "An pushable chair." +[ + mass(integer) : "Weight" : 400 + health(integer) : "Strength" : 25 +] +@PointClass base(Appearflags, Angle) size(-16 -16 -26, 16 16 26) color(0 128 204) studio("models\props\chair\chair.mdx") = props2_chair_push : "A pushable chair." +[ + mass(integer) : "Weight" : 400 + health(integer) : "Strength" : 25 +] +@PointClass base(Appearflags, Angle) size(-4 -85 -25, 4 85 25) color(0 128 204) studio("models/props/clothes/tris.md2") = props2_clothesline : "A clothes line." +[ + spawnflags(Flags) = + [ + 2 : "DONOTMOVE" : 0 + ] +] +@PointClass base(Appearflags, Angle) size(-32 -32 -24, 32 32 24) color(0 128 204) studio("models/props/clubchair/tris.md2") = props2_clubchair : "A pushable chair." +[ + mass(integer) : "Weight" : 400 + health(integer) : "Strength" : 25 +] +@PointClass base(Appearflags, Angle) size(-32 -64 -24, 32 64 24) color(0 128 204) studio("models/props/clubcouch/tris.md2") = props2_clubcouch : "A couch, the bounding box can be rotated in angles of 90 deg and block properly." [] +@PointClass base(Appearflags, Angle) size(-32 -26 -7, 32 26 7) color(0 128 204) studio("models\props\dead_fem\body.mdx;models\props\dead_fem\legs.mdx") = props2_deadgal_headless : "An headless female body you can shoot, the bounding box can be rotated in angles of 90 deg and block properly." +[ + health(integer) : "Strength" : 50 + item(string) : "Item to spawn when gibbed" +] +@PointClass base(Appearflags, Angle) size(-40 -27 -9, 40 27 9) color(0 128 204) studio("models\props\deadguy\body.mdx;models\props\deadguy\head.mdx;models\props\deadguy\legs.mdx") = props2_deadguy : "A dead guy body you can shoot, the bounding box can be rotated in angles of 90 deg and block properly." +[ + health(integer) : "Strength" : 50 + item(string) : "Item to spawn when gibbed" +] +@PointClass base(Appearflags, Angle) size(-17 -50 0, 13 30 88) color(0 128 204) studio("models\props\cementguy\body.mdx;models\props\cementguy\head.mdx;models\props\cementguy\legs.mdx") = props2_deadguy_underwater : "A drown guy in cement you can shoot, the bounding box can be rotated in angles of 90 deg and block properly." +[ + health(integer) : "Strength" : 50 + item(string) : "Item to spawn when gibbed" +] +@PointClass base(Appearflags, Angle) size(-12 -12 0, 12 12 10) color(0 128 204) studio("models\actors\shrimp\shrimp.mdx") = props2_fish : "A shrimp." +[ + option(integer) : "If set to '1', will not appear if the cvar 'props' is '0'" + dmg(integer) : "Shrimp bite damage" : 2 + health(integer) : "Health" : 10 +] +@PointClass base(Appearflags, Target, Angle) size(-16 -16 -16, 16 16 16) color(0 128 204) = props2_fish_spawner : "Base shrimp spawner, props2_fish_spawner_node determine possible spawn point." +[ + option(integer) : "If set to '1', will not appear if the cvar 'props' is '0'" + dmg(integer) : "Shrimp bite damage" : 2 + health(integer) : "Health" : 10 + deadticks(integer) : "Total number of shrimps in level from spawner at a time" : 5 +] +@PointClass base(Appearflags, Targetname, Angle) size(-16 -16 -16, 16 16 16) color(0 128 204) = props2_fish_spawner_node : "Possible shrimp spawn point for props2_fish_spawner" [] +@PointClass base(Appearflags, Targetname, Angle) size(-12 -12 0, 12 12 10) color(0 128 204) studio("models\actors\shrimp\shrimp.mdx") = props2_fish_trigger : "A shrimp that is spawned when triggered." +[ + option(integer) : "If set to '1', will not appear if the cvar 'props' is '0'" + dmg(integer) : "Shrimp bite damage" : 2 + health(integer) : "Health" : 10 +] +@PointClass base(Appearflags, Angle) size(-47 -6 -100, 47 6 100) color(0 128 204) + model( + {{ + spawnflags & 2 -> "models/props/flag/flag1.md2", + spawnflags & 4 -> "models/props/flag/flag2.md2", + spawnflags & 8 -> "models/props/flag/flag3.md2", + "models/props/flag/flag1.md2" + }} + ) = props2_flag : "A flag, the bounding box can be rotated in angles of 90 deg and block properly." +[ + spawnflags(flags) = + [ + 2 : "Flag1" : 0 + 4 : "Flag2" : 0 + 8 : "Flag3" : 0 + ] +] +@PointClass base(Appearflags, Angle) size(-47 -22 -50, 47 22 50) color(0 128 204) studio("models/props/gargoyle/tris.md2") = props2_gargoyle : "A stone gargoyle." [] +@PointClass base(Appearflags, Targetname, Angle) size(-16 -16 -16, 16 16 16) color(0 128 204) studio("models/props/helicopter/helicopter.mdx;models/props/helicopter/rotor.mdx;models/props/helicopter/legs.mdx;models/props/helicopter/body.mdx;models/props/helicopter/foot.mdx;models/props/helicopter/head.mdx") = props2_helicopter_animate : "A helicopter and actor (Blunt) that animate when trigered." [] +@PointClass base(Appearflags, Angle) size(-16 -16 -88, 16 16 -40) color(0 128 204) studio("models\props\litecone\litecone.mdx") = props2_lighthouse_beam : "A light house light beam that rotates." +[ + reactdelay(integer) : "Light distance from center" : 40 +] +@PointClass base(Appearflags, Angle) size(-10 -7 -5, 10 7 5) color(0 128 204) studio("models\props\lunch_set\tris.md2") = props2_lunch : "A lunch." [] +@PointClass base(Appearflags, Targetname, Angle) size(-42 -18 -38, 42 18 38) color(0 128 204) studio("models\props\pin1\pinball_m.mdx;models\props\pinball\ball.mdx;models\props\pinball\glass.mdx") = props2_pinball_machine : "A pinball machine, the bounding box can be rotated in angles of 90 deg and block properly, animate when triggered." +[ +//MDX not working yet but need diffrent model loading + spawnflags(Flags) = + [ + 2 : "PINNUM1" : 0 + 4 : "PINNUM2" : 0 + 8 : "PINNUM2" : 0 + ] +] +@PointClass base(Appearflags, Angle) size(-9 -11 -32, 9 11 32) color(0 128 204) studio("models\props\bush\tris.md2") = props2_plant_bush : "A bush like plant." +[ + health(integer) : "Strength" : 25 +] +@PointClass base(Appearflags, Angle) size(-50 -46 -40, 50 46 40) color(0 128 204) studio("models\props\fern\tris.md2") = props2_plant_fern : "A fern plant." +[ + health(integer) : "Strength" : 25 +] +@PointClass base(Appearflags, Angle) size(-12 -9 -20, 12 9 20) color(0 128 204) studio("models\props\plants\plant_sm.md2") = props2_plant_SM : "A plant small." +[ + health(integer) : "Strength" : 25 +] +@PointClass base(Appearflags, Angle) size(-50 -46 -53, 50 46 53) color(0 128 204) studio("models\props\plants\plant_xl.md2") = props2_plant_XL : "A plant big." +[ + health(integer) : "Strength" : 25 +] +@PointClass base(Appearflags, Angle) size(-60 -20 -56, 60 20 66) color(0 128 204) studio("models/props/shelfmetal1/shelf1.mdx;models/props/shelfmetal1/tanktops.mdx;models/props/shelfmetal1/shelf1.mdx;models/props/shelfmetal1/shelf2.mdx;models/props/shelfmetal1/barre1.mdx;models/props/shelfmetal1/barre2.mdx;models/props/shelfmetal1/barre3.mdx;models/props/shelfmetal1/barre4.mdx;models/props/shelfmetal1/tank_lg1.mdx;models/props/shelfmetal1/tank_lg2.mdx;models/props/shelfmetal1/tank_lg3.mdx;models/props/shelfmetal1/tank_sm.mdx;models/props/shelfmetal1/tank_sm1.mdx;models/props/shelfmetal1/tank_sm2.mdx;models/props/shelfmetal1/barreltops.mdx") = props2_shelf_metal_A_fall : "A falling metal shelf, bounding box can be rotated in angles of 90 deg and block properly." [] +@PointClass base(Appearflags, Angle) size(-60 -20 -56, 60 20 66) color(0 128 204) studio("models/props/shelfmetal2/shelf1.mdx;models/props/shelfmetal2/tanktops.mdx;models/props/shelfmetal2/shelf1.mdx;models/props/shelfmetal2/shelf2.mdx;models/props/shelfmetal2/barre1.mdx;models/props/shelfmetal2/barre2.mdx;models/props/shelfmetal2/barre3.mdx;models/props/shelfmetal2/barre4.mdx;models/props/shelfmetal2/cartboard1.mdx;models/props/shelfmetal2/cartboard2.mdx;models/props/shelfmetal2/tank_lg1.mdx;models/props/shelfmetal2/tank_lg2.mdx;models/props/shelfmetal2/tank_sm.mdx;models/props/shelfmetal2/tank_sm1.mdx;models/props/shelfmetal2/tank_sm2.mdx;models/props/shelfmetal2/barreltops.mdx") = props2_shelf_metal_B_fall : "Another falling metal shelf, bounding box can be rotated in angles of 90 deg and block properly." [] +@PointClass base(Appearflags, Angle) size(-4 -44 -44, 4 44 44) color(0 128 204) studio("models\props\sign\sign.mdx;models\props\sign\bar.mdx") = props2_sign : "A bar swingin sign, the bounding box can be rotated in angles of 90 deg and block properly.a" [] +@PointClass base(Appearflags, Targetname) size(-61 -148 -78, 61 148 78) color(0 128 204) studio("models/props/truck/box.mdx;models/props/truck/c4.mdx;models/props/truck/m26y.mdx;models/props/truck/mn3.mdx;models/props/truck/mp1a.mdx;models/props/truck/tires.mdx;models/props/truck/v1a.mdx") = props2_truck_die : "An exploding truck, animated when triggered." [] +@PointClass base(Appearflags, Angle) size(-16 -16 -24, 16 16 24) color(0 128 204) studio("models/props/vase1/tris.md2") = props2_vaseA : "A breakable vase." +[ + health(integer) : "Strength" : 25 +] +@PointClass base(Appearflags, Angle) size(-16 -16 -24, 16 16 24) color(0 128 204) studio("models/props/vase2/tris.md2") = props2_vaseB : "A breakable vase." +[ + health(integer) : "Strength" : 25 +] +@PointClass base(Appearflags, Angle) size(-2 -40 -12, 2 40 12) color(0 128 204) studio("models\props\fish\tris.md2") = props2_wall_fish : "A fish on the wall, the bounding box can be rotated in angles of 90 deg and block properly." [] + + + + +@PointClass base(Appearflags, Targetname, Angle) size(-44 -60 -49, 44 60 49) color(0 128 204) studio("models/props/nikki1/barrel_v4.mdx;models/props/nikki1/top_barrel_v4.mdx") = props3_barrels_fall_nikki_A : "A set of exploding barrels, must be triggered. This set is used in pv_boss." [] +@PointClass base(Appearflags, Targetname, Angle) size(-24 -48 -24, 24 48 24) color(0 128 204) studio("models/props/nikki2/barrel_v4.mdx;models/props/nikki2/top_barrel_v4.mdx") = props3_barrels_fall_nikki_B : "A set of exploding barrels, must be triggered. This set is used in pv_boss." [] +@PointClass base(Appearflags, Angle) size(-12 -11 -5, 12 11 5) color(0 128 204) studio("models\props\cash\cashstack.mdx") = props3_cash : "Some cash (model only, not a collectible item)." [] +@PointClass base(Appearflags, Targetname, Angle) size(-12 -14 -8, 12 18 7) color(0 128 204) studio("models\props\bill_counter\cashstack.mdx;models\props\bill_counter\numbers.mdx;models\props\bill_counter\machine.mdx;") = props3_cash_counter_animate : "A cash counter machine that animates when triggered." [] +@PointClass base(Appearflags, Targetname) size(-16 -16 -16, 16 16 16) color(0 128 204) studio("models\props\kpcut1\body.mdx;models\props\kpcut1\legs.mdx;models\props\kpcut1\head.mdx;") = props3_cut_A_animate : "The boss (Kingpin) sitting on a chair, will animate when triggered." [] +@PointClass base(Appearflags, Targetname) size(-16 -16 -16, 16 16 16) color(0 128 204) studio("models\props\kpcut2\body.mdx;models\props\kpcut2\legs.mdx;models\props\kpcut2\head.mdx;") = props3_cut_B_animate : "Talking boss (Kingpin), will animate when triggered." [] +@PointClass base(Appearflags, Targetname) size(-16 -16 -16, 16 16 16) color(0 128 204) studio("models\props\cutbc\body_chick.mdx;models\props\cutbc\legs_chick.mdx;models\props\cutbc\head_chick.mdx;models\props\cutbc\body.mdx;models\props\cutbc\legs.mdx;models\props\cutbc\head.mdx;models\props\cutbc\cigar.mdx") = props3_cut_boss_chick_animate : "A boss (Kingpin) and chick (Blunt) that animate on a balcony when trigered." [] +@PointClass base(Appearflags, Targetname) size(-16 -16 -16, 16 16 16) color(0 128 204) studio("models\props\player\bodyP.mdx;models\props\player\legsP.mdx;models\props\player\headP.mdx;models\props\boss\body_boss.mdx;models\props\boss\legs_boss.mdx;models\props\boss\head_boss.mdx") = props3_cut_boss_player_animate : "A boss (Nikki Blanco) and player that animate when trigered." [] +@PointClass base(Appearflags, Targetname) size(-16 -16 -16, 16 16 16) color(0 128 204) studio("models\props\kpcut3\body.mdx;models\props\kpcut3\legs.mdx;models\props\kpcut3\head.mdx;") = props3_cut_C_animate : "Talking boss (Kingpin), will animate when triggered." [] +@PointClass base(Appearflags, Targetname) size(-16 -16 -16, 16 16 16) color(0 128 204) studio("models\props\kpcut4\body.mdx;models\props\kpcut4\legs.mdx;models\props\kpcut4\head.mdx;") = props3_cut_D_animate : "Talking boss (Kingpin), will animate when triggered." [] +@PointClass base(Appearflags, Targetname) size(-16 -16 -16, 16 16 16) color(0 128 204) studio("models\props\finale\body_bossf.mdx;models\props\finale\legs_bossf.mdx;models\props\finale\head_bossf.mdx;models\props\finale\cigarf.mdx") = props3_cut_final_animate : "The final cut scene (thug standing, then sitting on a chair), animated when triggered." [] +@PointClass base(Appearflags, Targetname) size(-16 -16 -16, 16 16 16) color(0 128 204) studio("models\props\run_to_car\body_boss.mdx;models\props\run_to_car\legs_boss.mdx;models\props\run_to_car\head_boss.mdx") = props3_cut_run_to_car_animate : "Nikki Blanco running to a car, animated when triggered." [] +@PointClass base(Appearflags, Targetname) size(-16 -16 -16, 16 16 16) color(0 128 204) studio("models\props\train_jump\bodyP.mdx;models\props\train_jump\legsP.mdx;models\props\train_jump\headP.mdx;") = props3_cut_train_run_animate : "A player running to a train, will animate when triggered." [] +@PointClass base(Appearflags, Targetname) size(-67 -16 -58, 0 17 8) color(0 128 204) studio("models\props\driver\body_driver.mdx;models\props\driver\legs_driver.mdx;models\props\driver\head_driver.mdx;models\props\driver\wheel.mdx") = props3_cut_truck_driver : "The guy driving a truck in shipyard cutscene, animate when triggered." [] +@PointClass base(Appearflags, Targetname) size(-16 -16 -16, 16 16 16) color(0 128 204) studio("models/props/kpcut4_pinball/body.mdx;models/props/kpcut4_pinball/head.mdx;models/props/kpcut4_pinball/legs.mdx") = props3_cut_pinball_guy_animate : "A cut scene of a boss (Kingpin) and his pinball machine." [] +@PointClass base(Appearflags, Angle) size(-40 -48 -14, 40 48 14) color(0 128 204) studio("models\props\louie\body.mdx;models\props\louie\head.mdx;models\props\louie\legs.mdx") = props3_dead_louie : "A dead Louie body you can shoot." +[ + health(integer) : "Strength" : 50 + item(string) : "Item to spawn when gibbed" +] +@PointClass base(Appearflags, Angle) size(-3 -5 -6, 3 5 6) color(0 128 204) studio("models\props\decanter\solid.mdx;models\props\decanter\glass.mdx") = props3_decanter : "A decanter." [] +@PointClass base(Appearflags, Angle) size(-32 -8 -58, 32 8 58) color(0 128 204) studio("models\props\deco_fixture\deco_fixture.mdx") = props3_deco_fixture : "A deco fixture." [] +@PointClass base(Appearflags, Angle) size(-2 -2 -2, 2 2 2) color(0 128 204) studio("models\props\whiskeyglass\solid.mdx;models\props\whiskeyglass\glass.mdx") = props3_whiskey_glass : "A glass of whiskey." [] + + +@PointClass size(-8 -8 -8, 8 8 8) color(255 0 0) = smoke_esm : "Smoke effect, extra-small" +[ + alphalevel(integer) : "Opacity level, 1 to 10 " +] +@PointClass size(-32 -32 -32, 32 32 32) color(255 0 0) = smoke_lg : "Smoke effect, large" +[ + alphalevel(integer) : "Opacity level, 1 to 10 " +] +@PointClass size(-24 -24 -24, 24 24 24) color(255 0 0) = smoke_med : "Smoke effect, medium" +[ + alphalevel(integer) : "Opacity level, 1 to 10 " +] +@PointClass size(-16 -16 -16, 16 16 16) color(255 0 0) = smoke_sm : "Smoke effect, small" +[ + alphalevel(integer) : "Opacity level, 1 to 10 " +] + + +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_blaster : "Fires a blaster bold in the set direction when triggered." +[ + spawnflags(Flags) = + [ + 1 : "No Trail" : 0 + 2 : "No Effects" : 0 + ] + dmg(integer) : "Damage" : 15 + speed(integer) : "Speed" : 1000 +] +@SolidClass base(Appearflags, Targetname) color(0 0 255) = target_character : "Use with target_string and func_clock" +[ + team(string) : "Team" + count(integer) : "Position in the string" +] +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_changelevel : "Load a new map when triggered. You can specify the info_player_start to use in the next map, adding its ID after a $ symbol (example: map2$start1 will load map2.bsp and use the info_player_start called start1). Put a * symbol before the next map name to create a new unit, so the game forget infos regarding visited levels (example: *map2)" +[ + map(string) : "Next map" +] +@PointClass base(Appearflags, Targetname, Target, Killtarget) color(128 128 128) size(-8 -8 -8, 8 8 8) = target_crosslevel_target : "Triggered by a trigger_crosslevel_trigger elsewhere within a unit. If multiple triggers are checked, all must be true. Delay, target and killtarget also work." +[ + spawnflags(Flags) = + [ + 1 : "Trigger 1" : 0 + 2 : "Trigger 2" : 0 + 4 : "Trigger 3" : 0 + 8 : "Trigger 4" : 0 + 16 : "Trigger 5" : 0 + 32 : "Trigger 6" : 0 + 64 : "Trigger 7" : 0 + 128 : "Trigger 8" : 0 + ] + delay(integer) : "Delay before using targets if the trigger has been activated)" : 1 + message(string) : "Message to display on trigger" +] +@PointClass base(Appearflags, Targetname, Target, Killtarget) color(128 128 128) size(-8 -8 -8, 8 8 8) = target_crosslevel_trigger : "Once this trigger is touched/used, any trigger_crosslevel_target with the same trigger number is automatically used when a level is started within the same unit. It is OK to check multiple triggers. Message, delay, target, and killtarget also work." +[ + spawnflags(Flags) = + [ + 1 : "Trigger 1" : 0 + 2 : "Trigger 2" : 0 + 4 : "Trigger 3" : 0 + 8 : "Trigger 4" : 0 + 16 : "Trigger 5" : 0 + 32 : "Trigger 6" : 0 + 64 : "Trigger 7" : 0 + 128 : "Trigger 8" : 0 + ] + delay(integer) : "Delay before using targets if the trigger has been activated)" : 1 + message(string) : "Message to display on trigger" +] +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_earthquake : "When triggered, this initiates a level-wide earthquake, all players and monsters are affected." +[ + speed(integer) : "Severity of quake" : 200 + count(integer) : "Duration of the quake" : 5 +] +@PointClass base(Appearflags, Targetname, Target) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_explosion : "Spawns an explosion when used." +[ + delay(integer) : "Wait time before explosion" + dmg(integer) : "How much radius damage should be done" : 0 + fxdensity(integer) : "explosion size -- 1 to 100" : 10 +] +@PointClass base(Appearflags, Targetname, Target) size(-8 -8 -8, 8 8 8) color(255 0 0) = target_fire : "Spawn a fire." +[ + fxdensity(integer) : "Size of fire -- 1 to 100)" : 10 + deadticks(integer) : "Random fire sections per frame" : 3 + duration(float) : "How long fire stay alive in seconds, last forever if -1" : "5.0" + dmg(integer) : "Damage per second" : 10 + reactdelay(integer) : "Fire spread factor -- 0.0 to 10.0" : 1 +] + +@PointClass base(Appearflags, Targetname) size(-8 -8 -8, 8 8 8) color(255 0 0) studio("models/weapons/sshell_md2/tris.md2") = target_flamethrower : "Shoots flame when triggered on, does not when triggered off." +[ + dmg(integer) : "Damage the flame does per frame" : 2 + fxdensity(integer) : "Set to 1 to start on" + deadticks(integer) : "Angle adjustment up and down -- -90 to 90" : 0 +] +@PointClass base(Appearflags, Targetname) size(-8 -8 -8, 8 8 8) color(255 0 255) = target_goal : "Can be triggered once only, Counts a goal completed. These are single use targets." +[ + noise(sound) : "Wav sound to play when triggered (default='misc/secret.wav')" +] +@PointClass base(Appearflags, Targetname, Target, Angle) color(0 128 204) size(-8 -8 -8, 8 8 8) = target_laser : "Fires a laser when triggered." +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + 2 : "Red" : 0 + 4 : "Green" : 0 + 8 : "Blue" : 0 + 16 : "Yellow" : 0 + 32 : "Orange" : 0 + 64 : "Fat" : 0 + ] + dmg(integer) : "Damage inflicted when blocked" : 1 +] +@PointClass base(Appearflags, Targetname, Target) color(0 128 204) size(-8 -8 -8, 8 8 8) = target_lightramp : "Light ramp" +[ + spawnflags(Flags) = + [ + 1 : "Toggle" : 0 + ] + speed(integer) : "How many seconds the ramping will take" + message(string) : "Two letters: starting lightlevel and ending lightlevel ('a'=dark to 'z'=bright)" +] +@PointClass base(Appearflags, Targetname, Angle) size(-8 -8 -8, 8 8 8) color(255 0 0) = target_mal_laser : "Mal's laser." +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + 2 : "Red" : 0 + 4 : "Green" : 0 + 8 : "Blue" : 0 + 16 : "Yellow" : 0 + 32 : "Orange" : 0 + 64 : "Fat" : 0 + ] + dmg(integer) : "Damage inflicted when blocked" : 5 + delay(float) : "Delay before first shot" : "0.1" + wait(float) : "Time between two shots" : "0.1" + +] +@PointClass base(Appearflags, Targetname) color(255 0 255) size(-8 -8 -8, 8 8 8) = target_secret : "Can be triggered once only, counts a secret found." +[ + message(string) : "Message to print" : "You have found a secret." + noise(sound) : "Wav sound to play when triggered (default='misc/secret.wav')" +] +@PointClass base(Appearflags, Targetname, Target, Angle) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_spawner : "Will spawn an entity when triggered, the spawned entity inherit this entity's spawnflags, angle and origin." +[ + speed(integer) : "Speed" +] +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_speaker : "Sound emitter, play a sound each time the entity is triggered, can be toggled on and off if LOOPED-ON or LOOPED-OFF is set (looped sounds are always 'attenuation=3', 'volume=1')" +[ + spawnflags(Flags) = + [ + 1 : "Looped On" : 0 + 2 : "Looped Off" : 0 + 4 : "Reliable" : 0 + ] + noise(sound) : "Sound (path/file.wav)" + attenuation(Choices) : "Attenuation" : 1 = + [ + -1 : "None, send to whole level" + 1 : "Normal fighting sounds" + 2 : "Idle sound level" + 3 : "Ambient sound level" + ] + volume(integer) : "Volume (0.0 - 1.0)" : 1 +] +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_splash : "A particle emitter, spawns particles when triggered." +[ + sounds(choices) : "Type of splash" : 2 = + [ + 1 : "Sparks" + 2 : "Blue water" + 3 : "Brown water" + 4 : "Slime" + 5 : "Lava" + 6 : "Blood" + 7 : "Fireworks" + 8 : "Smoke" + ] + count(integer) : "Amount of particles -- 1 to 10" :3 + dmg(integer) : "Radius damage" : 0 + alphalevel(integer) : "Smoke only: Opacity level -- 1 to 10": 24 + firetype(integer) : "Smoke only: Smoke size -- 5 to 32" : 24 + deadticks(integer) : "Smoke only: Lifetime in seconds -- 1 to 60" : 6 + fxdensity(integer) : "Smoke only: Speed of rising -- 1 to 100 " : 25 + rotate(string) : "Smoke only: X Y Z velocity (default=up)" +] +@PointClass base(Appearflags, Targetname) color(0 0 255) size(-8 -8 -8, 8 8 8) = target_string : "String" +[ + team(string) : "Team" + message(string) : "Message to display on trigger" +] +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_temp_entity : "Fire an origin based temp entity event to the clients." +[ + style(string) : "type byte" +] + + + +@PointClass base(Appearflags, Target, Killtarget) color(128 128 128) size(-8 -8 -8, 8 8 8) = trigger_always : "This trigger will always fire. It is activated by the world." +[ + delay(integer) : "Wait before triggering targeted entities" +] +@SolidClass base(Appearflags, Targetname, Target, Killtarget) color(128 128 128) = trigger_counter : "Acts as an intermediary for an action that takes multiple inputs. If the cvar 'developer' is '1' and 'nomessage' is unset, each time this entity is triggered, the message X more to go... will appear (and Armageddon virus installed successfully when the sequence is completed)" +[ + spawnflags(Flags) = + [ + 1 : "No Message" : 0 + ] + count(integer) : "Number of times this trigger must be activated before triggering its targets" : 2 +] +@PointClass base(Appearflags, Targetname, Target) color(76 25 153) = trigger_elevator : "Elevator trigger" [] +@SolidClass base(Appearflags) color(128 128 128) = trigger_gravity : "Changes the touching entites gravity to the value of gravity." +[ + gravity(integer) : "Gravity (standard = 1.0)" : 1 +] +@SolidClass base(Appearflags, Targetname) color(128 128 128) = trigger_hurt : "Any entity taking damage touching this trigger will loose 'dmg' health points each server frame (or every second if SLOW spawnflag is set)." +[ + spawnflags(Flags) = + [ + 1 : "Start Off" : 0 + 2 : "Toggle" : 0 + 4 : "Silent" : 0 + 8 : "No Protection" : 0 + 16 : "Slow hurt" : 0 + ] + dmg(integer) : "Damages inflicted when touched." : 5 +] +@SolidClass base(Appearflags, Targetname) color(128 128 128) = trigger_hurt_electric : "Any entity taking damage touching this trigger will be electrocuted and loose 'dmg' health points each server frame (or every second if SLOW spawnflag is set)." +[ + spawnflags(Flags) = + [ + 1 : "Start Off" : 0 + 2 : "Toggle" : 0 + 4 : "Silent" : 0 + 8 : "No Protection" : 0 + 16 : "Slow hurt" : 0 + ] + dmg(integer) : "Damages inflicted when touched." : 5 +] +@SolidClass base(Appearflags, Targetname) color(128 128 128) = trigger_hurt_fire : "Any entity taking damage touching this trigger will burn and loose 'dmg' health points each server frame (or every second if SLOW spawnflag is set)." +[ + spawnflags(Flags) = + [ + 1 : "Start Off" : 0 + 2 : "Toggle" : 0 + 4 : "Silent" : 0 + 8 : "No Protection" : 0 + 16 : "Slow hurt" : 0 + ] + dmg(integer) : "Damages inflicted when touched." : 5 +] +@PointClass base(Appearflags, Targetname, Target, Killtarget) color(128 128 128) size(-8 -8 -8, 8 8 8) = trigger_key : "A relay trigger that only fires it's targets if player has the proper key." +[ + item(string) : "Item classname" : "Item required (pickup name)" +] +@SolidClass base(Appearflags, Angle) color(128 128 128) = trigger_monsterjump : "Walking monsters that touch this entity will jump in the direction of the trigger's angle." +[ + speed(integer) : "Speed thrown forward" : 200 + height(integer) : "Height thrown upward" : 200 +] +@SolidClass base(Appearflags, Target, Killtarget) = trigger_motorcycle : "Skidrow only, will trigger the motorcycle cutscene script. If 'Battery' is in player's inventory, the item is taken away, the targeted entity is triggered, every 'props_motorcycle' entities are removed from the map while a new entity is spawned to make the cutscene animation. If 'Battery' is not in player's inventory, EP_SKIDROW_FOUND_BIKE flag is registered (Found the bike... Broken down piece of junk doesn't have a battery...) and nothing else happen." [] +@SolidClass base(Appearflags, Targetname, Target, Killtarget) = trigger_multiple : "Repeatable trigger. Must be targeted at one or more entities." +[ + spawnflags(Flags) = + [ + 1 : "Monster" : 0 + 2 : "Not Player" : 0 + 2 : "Triggered" : 0 + ] + wait(float) : "Seconds between triggers" : "0.2" + delay(integer) : "Wait before triggering targeted entities" + message(string) : "String to be displayed when triggered" + sounds(choices) : "Sounds" : 0 = + [ + 0 : "Silent" + 1 : "misc/secret.wav" + 2 : "misc/talk.wav" + 3 : "misc/trigger1.wav" + ] +] +@SolidClass base(Appearflags, Targetname, Target, Killtarget) = trigger_once : "Triggers once, then removes itself. You must set the key 'target' to the name of another object in the level that has a matching 'targetname'. If TRIGGERED is set, this trigger must be triggered before it is live." +[ + spawnflags(Flags) = + [ + 4 : "Triggered" : 0 + 8 : "Sceneric" : 0 + ] + delay(integer) : "Wait before triggering targeted entities" + message(string) : "String to be displayed when triggered" + sounds(choices) : "Sounds" : 0 = + [ + 0 : "Silent" + 1 : "misc/secret.wav" + 2 : "misc/talk.wav" + 3 : "misc/trigger1.wav" + ] +] +@SolidClass base(Appearflags, Angle) = trigger_push : "Pushes the player." +[ + spawnflags(Flags) = + [ + 1 : "Push Once" : 0 + ] + speed(integer) : "Speed of push" : 1000 +] +@PointClass base(Appearflags, Targetname, Target, Killtarget) color(128 128 128) = trigger_relay : "This fixed size trigger cannot be touched, it can only be fired by other events." +[ + delay(integer) : "Time in seconds before triggering the target" + message(string) : "Trigger message" +] +@SolidClass base(Appearflags, Targetname, Target) = trigger_unlock : "Player will unlock a targeted door when this brush is touched, can also be triggered (door's 'key' must be '-1')" [] + + +@baseclass base(Appearflags, Targetname, Target, Killtarget, Angle) size(-16 -16 -16, 16 16 16) color(77 77 255) = WeaponClass [] +@PointClass base(WeaponClass) studio("models/weapons/g_rocket_launcher/tris.md2") = weapon_bazooka : "Rocket launcher (clip size: 3) -- Requires ammo_rockets." [] +@PointClass base(WeaponClass) studio("models/weapons/g_crowbar/tris.md2") = weapon_crowbar : "Crowbar (no clip) -- Melee weapon." [] +@PointClass base(WeaponClass) studio("models/pu_icon/flame_shell/tris.md2") = weapon_flamethrower : "Flame thrower (no clip) -- Requires ammo_flametank." [] +@PointClass base(WeaponClass) studio("models/weapons/g_grenade_launcher/tris.md2") = weapon_grenadelauncher : "Grenade launcher (clip size: 3) -- Requires ammo_grenades." [] +@PointClass base(WeaponClass) studio("models/weapons/g_hmg/tris.md2") = weapon_heavymachinegun : "Heavy submachine gun (clip size: 30) -- Requires ammo_308, can be equipped with Cooling Sleeves (hmg_mod_cooling)." [] +@PointClass base(WeaponClass) studio("models/weapons/g_pistol/tris.md2") = weapon_pistol : "Standard pistol (clip size: 10) -- Requires ammo_bullets or ammo_cylinder, can be equipped with magnum mod (pistol_mod_damage), rate of fire (pistol_mod_rof), reload (pistol_mod_reload)." [] +@PointClass base(WeaponClass) studio("models/weapons/g_shotgun/tris.md2") = weapon_shotgun : "Shotgun (clip size: 8) -- Requires ammo_shells." [] +@PointClass base(WeaponClass) studio("models/weapons/silencer_mdx/pistol.mdx") = weapon_spistol : "Pistol with silencer (clip size: 10) -- Requires ammo_bullets or ammo_cylinder can be equipped with magnum mod (pistol_mod_damage), rate of fire (pistol_mod_rof), reload (pistol_mod_reload). Silencer lasts 20 shots before breaking up." [] +@PointClass base(WeaponClass) studio("models/weapons/g_tomgun/tris.md2") = weapon_tommygun : "Thompson submachine gun (clip size: 50) -- Requires ammo_bullets or ammo_cylinder." [] + + + + +@PointClass base(Appearflags, Targetname, Target, Killtarget, Angle) size(-16 -16 -16, 16 16 16) color(77 77 255) = item_jetpack : "Pickup item: jetpack ('Jetpack'). No model and broken code." [] +@PointClass base(Appearflags, Targetname, Angle) size(-2 -2 -12, 2 2 12) color(0 255 0) studio("models\objects\minelite\light1\tris.md2") = light_mine1 : "Dusty fluorescent light fixture" +[ + light(integer) : "Brightness" : 300 + style(Choices) : "Style" : 0 = + [ + 0 : "Normal" + 1 : "Fire Flicker #1" + 2 : "Slow Strong Pulse" + 3 : "Candle #1" + 4 : "Fast Strobe" + 5 : "Gentle Pulse #1" + 6 : "Fire Flicker #2" + 7 : "Candle #2" + 8 : "Candle #3" + 9 : "Slow Strong Strobe" + 10 : "Fluorescent Flicker #1" + 11 : "Slow pulse, no black" + 12 : "Fire Flicker #3" + 13 : "Fluorescent Flicker #2" + 14 : "Fluorescent Flicker #3" + 15 : "Realistic Fade #1" + 16 : "Realistic Fade #2" + 17 : "Slow Strongstrobe (out of phase)" + 18 : "Three Cycle Strobe #1" + 19 : "Three Cycle Strobe #2" + 20 : "Three Cycle Strobe #3" + ] + _color(string) : "Defines the color in scalar R G B values" : "0 0 0" +] +@PointClass base(Appearflags, Targetname, Angle) size(-2 -2 -12, 2 2 12) color(0 255 0) studio("models\objects\minelite\light2\tris.md2") = light_mine2 : "Clean fluorescent light fixture" +[ + light(integer) : "Brightness" : 300 + style(Choices) : "Style" : 0 = + [ + 0 : "Normal" + 1 : "Fire Flicker #1" + 2 : "Slow Strong Pulse" + 3 : "Candle #1" + 4 : "Fast Strobe" + 5 : "Gentle Pulse #1" + 6 : "Fire Flicker #2" + 7 : "Candle #2" + 8 : "Candle #3" + 9 : "Slow Strong Strobe" + 10 : "Fluorescent Flicker #1" + 11 : "Slow pulse, no black" + 12 : "Fire Flicker #3" + 13 : "Fluorescent Flicker #2" + 14 : "Fluorescent Flicker #3" + 15 : "Realistic Fade #1" + 16 : "Realistic Fade #2" + 17 : "Slow Strongstrobe (out of phase)" + 18 : "Three Cycle Strobe #1" + 19 : "Three Cycle Strobe #2" + 20 : "Three Cycle Strobe #3" + ] + _color(string) : "Defines the color in scalar R G B values" : "0 0 0" +] +@PointClass base(Appearflags, Angle) size(-8 -8 -8, 8 8 8) color(255 0 0) studio("models/objects/gibs/arm/tris.md2") = misc_gib_arm : "Gib Arm. Q2 leftover." [] +@PointClass base(Appearflags, Angle) size(-8 -8 -8, 8 8 8) color(255 0 0) studio("models/objects/gibs/head/tris.md2") = misc_gib_head : "Gib Head. Q2 leftover." [] +@PointClass base(Appearflags, Angle) size(-8 -8 -8, 8 8 8) color(255 0 0) studio("models/objects/gibs/leg/tris.md2") = misc_gib_leg : "Gib Leg. Q2 leftover." [] +@PointClass base(Appearflags, Target, Angle) size(-32 -32 -24, 32 32 -16) color(255 0 0) studio("models\objects\dmspot\tris.md2") = misc_teleporter : "Stepping onto this disc will teleport players to the targeted 'misc_teleporter_dest' object." [] +@PointClass base(Appearflags, Targetname, Angle) size(-32 -32 -24, 32 32 -16) color(255 0 0) model({ "path" : "models\objects\dmspot\tris.md2", "skin" : 1 }) = misc_teleporter_dest : "Teleporter destination point." [] +@PointClass base(Appearflags, Targetname) size(-8 -8 -8, 8 8 8) color(0 128 204) studio("models/props/light/tris.md2") = rotating_light : "a rotating light. From Q2 Xatrix mod." +[ + health(integer) : "Strength, the light can be destroyed if set" + speed(integer) : "Light radius" :32 + spawnflags(flags) = + [ + 1 : "Start Off" : 0 + 2 : "Alarm" : 0 + ] +] + + + + + diff --git a/tools/trenchbroom/games/Neverball/GameConfig.cfg b/tools/trenchbroom/games/Neverball/GameConfig.cfg new file mode 100644 index 0000000..5be8ed2 --- /dev/null +++ b/tools/trenchbroom/games/Neverball/GameConfig.cfg @@ -0,0 +1,66 @@ +{ + "version": 9, + "name": "Neverball", + "icon": "Icon.png", + "experimental": true, + "fileformats": [ + { "format": "Quake3", "initialmap": "initial_neverball_map.map" } + ], + "filesystem": { + "searchpath": ".", + "packageformat": { "extension": ".zip", "format": "zip" } + }, + "materials": { + "root": "textures", + "extensions": [".jpg", ".jpeg", ".tga", ".png"] + }, + "entities": { + "definitions": [ "neverball.fgd" ], + "defaultcolor": "0.6 0.6 0.6 1.0" + }, + "tags": { + "brush": [ + ], + "brushface": [ + ] + }, + "faceattribs": { + "surfaceflags": [ + ], + "contentflags": [ + // Setting ANY flags here will cause the brush to turn into a detail brush. + // However, it's not wise to rely on this. + { "unused": true }, // 1 + { "unused": true }, // 2 + { "unused": true }, // 4 + { "unused": true }, // 8 + { "unused": true }, // 16 + { "unused": true }, // 32 + { "unused": true }, // 64 + { "unused": true }, // 128 + { "unused": true }, // 256 + { "unused": true }, // 512 + { "unused": true }, // 1024 + { "unused": true }, // 2048 + { "unused": true }, // 4096 + { "unused": true }, // 8192 + { "unused": true }, // 16384 + { "unused": true }, // 32768 + { "unused": true }, // 65536 + { "unused": true }, // 131072 + { "unused": true }, // 262144 c0 + { "unused": true }, // 524288 c9 + { "unused": true }, // 1048576 c1 + { "unused": true }, // 2097152 c2 + { "unused": true }, // 4194304 cu + { "unused": true }, // 8388608 cd + { "unused": true }, // 16777216 o + { "unused": true }, // 33554432 m + { "unused": true }, // 67108864 c + { + "name": "detail", + "description": "The brush cannot be collided with." + } + ] + } +} diff --git a/tools/trenchbroom/games/Neverball/Icon.png b/tools/trenchbroom/games/Neverball/Icon.png new file mode 100644 index 0000000..2ce17c7 Binary files /dev/null and b/tools/trenchbroom/games/Neverball/Icon.png differ diff --git a/tools/trenchbroom/games/Neverball/assets/__tb_generic_ring_05.obj b/tools/trenchbroom/games/Neverball/assets/__tb_generic_ring_05.obj new file mode 100644 index 0000000..858d7fb --- /dev/null +++ b/tools/trenchbroom/games/Neverball/assets/__tb_generic_ring_05.obj @@ -0,0 +1,326 @@ +# Blender v2.79 (sub 0) OBJ File: '' +# www.blender.org +mtllib __tb_generic_ring_05.mtl +o Circle +v 0.000000 -0.010000 -0.500000 +v 0.000000 0.010000 -0.500000 +v -0.097545 -0.010000 -0.490393 +v -0.097545 0.010000 -0.490393 +v -0.191342 -0.010000 -0.461940 +v -0.191342 0.010000 -0.461940 +v -0.277785 -0.010000 -0.415735 +v -0.277785 0.010000 -0.415735 +v -0.353553 -0.010000 -0.353553 +v -0.353553 0.010000 -0.353553 +v -0.415735 -0.010000 -0.277785 +v -0.415735 0.010000 -0.277785 +v -0.461940 -0.010000 -0.191342 +v -0.461940 0.010000 -0.191342 +v -0.490393 -0.010000 -0.097545 +v -0.490393 0.010000 -0.097545 +v -0.500000 -0.010000 -0.000000 +v -0.500000 0.010000 -0.000000 +v -0.490393 -0.010000 0.097545 +v -0.490393 0.010000 0.097545 +v -0.461940 -0.010000 0.191342 +v -0.461940 0.010000 0.191342 +v -0.415735 -0.010000 0.277785 +v -0.415735 0.010000 0.277785 +v -0.353553 -0.010000 0.353553 +v -0.353553 0.010000 0.353553 +v -0.277785 -0.010000 0.415735 +v -0.277785 0.010000 0.415735 +v -0.191342 -0.010000 0.461940 +v -0.191342 0.010000 0.461940 +v -0.097545 -0.010000 0.490393 +v -0.097545 0.010000 0.490393 +v 0.000000 -0.010000 0.500000 +v 0.000000 0.010000 0.500000 +v 0.097545 -0.010000 0.490393 +v 0.097545 0.010000 0.490393 +v 0.191342 -0.010000 0.461940 +v 0.191342 0.010000 0.461940 +v 0.277785 -0.010000 0.415735 +v 0.277785 0.010000 0.415735 +v 0.353554 -0.010000 0.353553 +v 0.353554 0.010000 0.353553 +v 0.415735 -0.010000 0.277785 +v 0.415735 0.010000 0.277785 +v 0.461940 -0.010000 0.191341 +v 0.461940 0.010000 0.191341 +v 0.490393 -0.010000 0.097545 +v 0.490393 0.010000 0.097545 +v 0.500000 -0.010000 -0.000000 +v 0.500000 0.010000 -0.000000 +v 0.490393 -0.010000 -0.097546 +v 0.490393 0.010000 -0.097546 +v 0.461940 -0.010000 -0.191342 +v 0.461940 0.010000 -0.191342 +v 0.415734 -0.010000 -0.277786 +v 0.415734 0.010000 -0.277786 +v 0.353553 -0.010000 -0.353554 +v 0.353553 0.010000 -0.353554 +v 0.277785 -0.010000 -0.415735 +v 0.277785 0.010000 -0.415735 +v 0.191341 -0.010000 -0.461940 +v 0.191341 0.010000 -0.461940 +v 0.097544 -0.010000 -0.490393 +v 0.097544 0.010000 -0.490393 +v -0.095585 0.000000 -0.480537 +v -0.187496 0.000000 -0.452656 +v -0.272203 0.000000 -0.407380 +v -0.346448 0.000000 -0.346448 +v -0.407380 0.000000 -0.272203 +v -0.452656 0.000000 -0.187496 +v -0.480537 0.000000 -0.095585 +v -0.489952 0.000000 -0.000000 +v -0.480537 0.000000 0.095585 +v -0.452656 0.000000 0.187496 +v -0.407380 0.000000 0.272203 +v -0.346448 0.000000 0.346448 +v -0.272203 0.000000 0.407380 +v -0.187496 0.000000 0.452656 +v -0.095585 0.000000 0.480537 +v 0.000000 0.000000 0.489952 +v 0.095585 0.000000 0.480537 +v 0.187497 0.000000 0.452656 +v 0.272203 0.000000 0.407380 +v 0.346448 0.000000 0.346448 +v 0.407380 0.000000 0.272202 +v 0.452656 0.000000 0.187496 +v 0.480537 0.000000 0.095584 +v 0.489952 0.000000 -0.000000 +v 0.480537 0.000000 -0.095585 +v 0.452656 0.000000 -0.187497 +v 0.407380 0.000000 -0.272203 +v 0.346448 0.000000 -0.346449 +v 0.272202 0.000000 -0.407380 +v 0.187496 0.000000 -0.452657 +v 0.095584 0.000000 -0.480537 +v 0.000000 0.000000 -0.489952 +vt 0.752056 0.544354 +vt 0.721292 0.573037 +vt 0.721292 0.573037 +vt 0.752056 0.544354 +vt 0.752056 0.544354 +vt 0.721292 0.573037 +vt 0.686848 0.596313 +vt 0.686848 0.596313 +vt 0.686848 0.596313 +vt 0.649924 0.614526 +vt 0.649924 0.614526 +vt 0.649924 0.614526 +vt 0.611380 0.628022 +vt 0.611380 0.628022 +vt 0.611380 0.628022 +vt 0.571835 0.637098 +vt 0.571835 0.637098 +vt 0.571835 0.637098 +vt 0.531738 0.641973 +vt 0.531738 0.641973 +vt 0.531738 0.641973 +vt 0.491439 0.642778 +vt 0.491439 0.642778 +vt 0.491439 0.642778 +vt 0.451245 0.639549 +vt 0.451245 0.639549 +vt 0.451245 0.639549 +vt 0.411471 0.632228 +vt 0.411471 0.632228 +vt 0.411471 0.632228 +vt 0.372499 0.620664 +vt 0.372499 0.620664 +vt 0.372499 0.620664 +vt 0.334832 0.604624 +vt 0.334832 0.604624 +vt 0.334832 0.604624 +vt 0.299166 0.583809 +vt 0.299166 0.583809 +vt 0.299166 0.583809 +vt 0.266473 0.557894 +vt 0.266473 0.557894 +vt 0.266473 0.557894 +vt 0.238090 0.526588 +vt 0.238090 0.526588 +vt 0.238090 0.526588 +vt 0.215813 0.489748 +vt 0.215813 0.489748 +vt 0.215813 0.489748 +vt 0.201957 0.447554 +vt 0.201957 0.447554 +vt 0.201957 0.447554 +vt 0.199317 0.400759 +vt 0.199317 0.400759 +vt 0.199317 0.400759 +vt 0.210951 0.351006 +vt 0.210951 0.351006 +vt 0.210951 0.351006 +vt 0.239648 0.301117 +vt 0.239648 0.301117 +vt 0.239648 0.301117 +vt 0.287027 0.255206 +vt 0.287027 0.255206 +vt 0.287027 0.255206 +vt 0.352412 0.218326 +vt 0.352412 0.218326 +vt 0.352412 0.218326 +vt 0.431934 0.195523 +vt 0.431934 0.195523 +vt 0.431934 0.195523 +vt 0.518563 0.190405 +vt 0.518563 0.190405 +vt 0.518563 0.190405 +vt 0.603452 0.203896 +vt 0.603452 0.203896 +vt 0.603452 0.203896 +vt 0.678181 0.233865 +vt 0.678181 0.233865 +vt 0.678181 0.233865 +vt 0.736792 0.275904 +vt 0.736792 0.275904 +vt 0.736792 0.275904 +vt 0.776664 0.324750 +vt 0.776664 0.324750 +vt 0.776664 0.324750 +vt 0.798126 0.375590 +vt 0.798126 0.375590 +vt 0.798126 0.375590 +vt 0.803402 0.424783 +vt 0.803402 0.424783 +vt 0.803402 0.424783 +vt 0.795515 0.470001 +vt 0.795515 0.470001 +vt 0.795515 0.470001 +vt 0.777511 0.510011 +vt 0.777511 0.510011 +vt 0.777511 0.510011 +vn 0.2053 -0.7071 0.6767 +vn 0.2053 0.7071 0.6767 +vn 0.3333 -0.7071 0.6236 +vn 0.3333 0.7071 0.6236 +vn 0.4486 -0.7071 0.5466 +vn 0.4486 0.7071 0.5466 +vn 0.5466 -0.7071 0.4486 +vn 0.5466 0.7071 0.4486 +vn 0.6236 -0.7071 0.3333 +vn 0.6236 0.7071 0.3333 +vn 0.6767 -0.7071 0.2053 +vn 0.6767 0.7071 0.2053 +vn 0.7037 -0.7071 0.0693 +vn 0.7037 0.7071 0.0693 +vn 0.7037 -0.7071 -0.0693 +vn 0.7037 0.7071 -0.0693 +vn 0.6767 -0.7071 -0.2053 +vn 0.6767 0.7071 -0.2053 +vn 0.6236 -0.7071 -0.3333 +vn 0.6236 0.7071 -0.3333 +vn 0.5466 -0.7071 -0.4486 +vn 0.5466 0.7071 -0.4486 +vn 0.4486 -0.7071 -0.5466 +vn 0.4486 0.7071 -0.5466 +vn 0.3333 -0.7071 -0.6236 +vn 0.3333 0.7071 -0.6236 +vn 0.2053 -0.7071 -0.6767 +vn 0.2053 0.7071 -0.6767 +vn 0.0693 -0.7071 -0.7037 +vn 0.0693 0.7071 -0.7037 +vn -0.0693 -0.7071 -0.7037 +vn -0.0693 0.7071 -0.7037 +vn -0.2053 -0.7071 -0.6767 +vn -0.2053 0.7071 -0.6767 +vn -0.3333 -0.7071 -0.6236 +vn -0.3333 0.7071 -0.6236 +vn -0.4486 -0.7071 -0.5466 +vn -0.4486 0.7071 -0.5466 +vn -0.5466 -0.7071 -0.4486 +vn -0.5466 0.7071 -0.4486 +vn -0.6236 -0.7071 -0.3333 +vn -0.6236 0.7071 -0.3333 +vn -0.6767 -0.7071 -0.2053 +vn -0.6767 0.7071 -0.2053 +vn -0.7037 -0.7071 -0.0693 +vn -0.7037 0.7071 -0.0693 +vn -0.7037 -0.7071 0.0693 +vn -0.7037 0.7071 0.0693 +vn -0.6767 -0.7071 0.2053 +vn -0.6767 0.7071 0.2053 +vn -0.6236 -0.7071 0.3333 +vn -0.6236 0.7071 0.3333 +vn -0.5466 -0.7071 0.4486 +vn -0.5466 0.7071 0.4486 +vn -0.4486 -0.7071 0.5466 +vn -0.4486 0.7071 0.5466 +vn -0.3333 -0.7071 0.6236 +vn -0.3333 0.7071 0.6236 +vn -0.2053 -0.7071 0.6767 +vn -0.2053 0.7071 0.6767 +vn -0.0693 -0.7071 0.7037 +vn -0.0693 0.7071 0.7037 +vn 0.0693 -0.7071 0.7037 +vn 0.0693 0.7071 0.7037 +usemtl mtrl/blue +s off +f 65/1/1 66/2/1 5/3/1 3/4/1 +f 66/2/2 65/1/2 4/5/2 6/6/2 +f 66/2/3 67/7/3 7/8/3 5/3/3 +f 67/7/4 66/2/4 6/6/4 8/9/4 +f 67/7/5 68/10/5 9/11/5 7/8/5 +f 68/10/6 67/7/6 8/9/6 10/12/6 +f 68/10/7 69/13/7 11/14/7 9/11/7 +f 69/13/8 68/10/8 10/12/8 12/15/8 +f 69/13/9 70/16/9 13/17/9 11/14/9 +f 70/16/10 69/13/10 12/15/10 14/18/10 +f 70/16/11 71/19/11 15/20/11 13/17/11 +f 71/19/12 70/16/12 14/18/12 16/21/12 +f 71/19/13 72/22/13 17/23/13 15/20/13 +f 72/22/14 71/19/14 16/21/14 18/24/14 +f 72/22/15 73/25/15 19/26/15 17/23/15 +f 73/25/16 72/22/16 18/24/16 20/27/16 +f 73/25/17 74/28/17 21/29/17 19/26/17 +f 74/28/18 73/25/18 20/27/18 22/30/18 +f 74/28/19 75/31/19 23/32/19 21/29/19 +f 75/31/20 74/28/20 22/30/20 24/33/20 +f 75/31/21 76/34/21 25/35/21 23/32/21 +f 76/34/22 75/31/22 24/33/22 26/36/22 +f 76/34/23 77/37/23 27/38/23 25/35/23 +f 77/37/24 76/34/24 26/36/24 28/39/24 +f 77/37/25 78/40/25 29/41/25 27/38/25 +f 78/40/26 77/37/26 28/39/26 30/42/26 +f 78/40/27 79/43/27 31/44/27 29/41/27 +f 79/43/28 78/40/28 30/42/28 32/45/28 +f 79/43/29 80/46/29 33/47/29 31/44/29 +f 80/46/30 79/43/30 32/45/30 34/48/30 +f 80/46/31 81/49/31 35/50/31 33/47/31 +f 81/49/32 80/46/32 34/48/32 36/51/32 +f 81/49/33 82/52/33 37/53/33 35/50/33 +f 82/52/34 81/49/34 36/51/34 38/54/34 +f 82/52/35 83/55/35 39/56/35 37/53/35 +f 83/55/36 82/52/36 38/54/36 40/57/36 +f 83/55/37 84/58/37 41/59/37 39/56/37 +f 84/58/38 83/55/38 40/57/38 42/60/38 +f 84/58/39 85/61/39 43/62/39 41/59/39 +f 85/61/40 84/58/40 42/60/40 44/63/40 +f 85/61/41 86/64/41 45/65/41 43/62/41 +f 86/64/42 85/61/42 44/63/42 46/66/42 +f 86/64/43 87/67/43 47/68/43 45/65/43 +f 87/67/44 86/64/44 46/66/44 48/69/44 +f 87/67/45 88/70/45 49/71/45 47/68/45 +f 88/70/46 87/67/46 48/69/46 50/72/46 +f 88/70/47 89/73/47 51/74/47 49/71/47 +f 89/73/48 88/70/48 50/72/48 52/75/48 +f 89/73/49 90/76/49 53/77/49 51/74/49 +f 90/76/50 89/73/50 52/75/50 54/78/50 +f 90/76/51 91/79/51 55/80/51 53/77/51 +f 91/79/52 90/76/52 54/78/52 56/81/52 +f 91/79/53 92/82/53 57/83/53 55/80/53 +f 92/82/54 91/79/54 56/81/54 58/84/54 +f 92/82/55 93/85/55 59/86/55 57/83/55 +f 93/85/56 92/82/56 58/84/56 60/87/56 +f 93/85/57 94/88/57 61/89/57 59/86/57 +f 94/88/58 93/85/58 60/87/58 62/90/58 +f 94/88/59 95/91/59 63/92/59 61/89/59 +f 95/91/60 94/88/60 62/90/60 64/93/60 +f 95/91/61 96/94/61 1/95/61 63/92/61 +f 96/94/62 95/91/62 64/93/62 2/96/62 +f 96/94/63 65/1/63 3/4/63 1/95/63 +f 65/1/64 96/94/64 2/96/64 4/5/64 diff --git a/tools/trenchbroom/games/Neverball/assets/__tb_info_player_deathmatch.obj b/tools/trenchbroom/games/Neverball/assets/__tb_info_player_deathmatch.obj new file mode 100644 index 0000000..6f61eed --- /dev/null +++ b/tools/trenchbroom/games/Neverball/assets/__tb_info_player_deathmatch.obj @@ -0,0 +1,326 @@ +# Blender v2.79 (sub 0) OBJ File: '' +# www.blender.org +mtllib __tb_info_player_deathmatch.mtl +o __tb_info_player_deathmatch +v -0.144357 -0.375000 -0.725734 +v -0.283167 -0.375000 -0.683626 +v -0.287013 -0.385000 -0.692910 +v -0.146318 -0.385000 -0.735589 +v -0.146318 -0.365000 -0.735589 +v -0.287013 -0.365000 -0.692910 +v -0.411095 -0.375000 -0.615247 +v -0.416678 -0.385000 -0.623602 +v -0.416678 -0.365000 -0.623602 +v -0.523225 -0.375000 -0.523225 +v -0.530330 -0.385000 -0.530330 +v -0.530330 -0.365000 -0.530330 +v -0.615247 -0.375000 -0.411095 +v -0.623602 -0.385000 -0.416678 +v -0.623602 -0.365000 -0.416678 +v -0.683626 -0.375000 -0.283167 +v -0.692910 -0.385000 -0.287013 +v -0.692910 -0.365000 -0.287013 +v -0.725734 -0.375000 -0.144357 +v -0.735589 -0.385000 -0.146318 +v -0.735589 -0.365000 -0.146318 +v -0.739952 -0.375000 0.000000 +v -0.750000 -0.385000 -0.000000 +v -0.750000 -0.365000 0.000000 +v -0.725734 -0.375000 0.144357 +v -0.735589 -0.385000 0.146318 +v -0.735589 -0.365000 0.146318 +v -0.683626 -0.375000 0.283167 +v -0.692910 -0.385000 0.287012 +v -0.692910 -0.365000 0.287012 +v -0.615247 -0.375000 0.411095 +v -0.623602 -0.385000 0.416678 +v -0.623602 -0.365000 0.416678 +v -0.523225 -0.375000 0.523225 +v -0.530330 -0.385000 0.530330 +v -0.530330 -0.365000 0.530330 +v -0.411095 -0.375000 0.615247 +v -0.416678 -0.385000 0.623602 +v -0.416678 -0.365000 0.623602 +v -0.283167 -0.375000 0.683626 +v -0.287012 -0.385000 0.692910 +v -0.287012 -0.365000 0.692910 +v -0.144357 -0.375000 0.725734 +v -0.146318 -0.385000 0.735589 +v -0.146318 -0.365000 0.735589 +v 0.000000 -0.375000 0.739952 +v 0.000000 -0.385000 0.750000 +v 0.000000 -0.365000 0.750000 +v 0.144358 -0.375000 0.725734 +v 0.146318 -0.385000 0.735589 +v 0.146318 -0.365000 0.735589 +v 0.283168 -0.375000 0.683626 +v 0.287013 -0.385000 0.692909 +v 0.287013 -0.365000 0.692909 +v 0.411095 -0.375000 0.615247 +v 0.416678 -0.385000 0.623602 +v 0.416678 -0.365000 0.623602 +v 0.523225 -0.375000 0.523224 +v 0.530330 -0.385000 0.530330 +v 0.530330 -0.365000 0.530330 +v 0.615248 -0.375000 0.411095 +v 0.623603 -0.385000 0.416677 +v 0.623603 -0.365000 0.416677 +v 0.683626 -0.375000 0.283167 +v 0.692910 -0.385000 0.287012 +v 0.692910 -0.365000 0.287012 +v 0.725734 -0.375000 0.144357 +v 0.735589 -0.385000 0.146317 +v 0.735589 -0.365000 0.146317 +v 0.739952 -0.375000 -0.000001 +v 0.750000 -0.385000 -0.000001 +v 0.750000 -0.365000 -0.000001 +v 0.725733 -0.375000 -0.144358 +v 0.735589 -0.385000 -0.146319 +v 0.735589 -0.365000 -0.146319 +v 0.683626 -0.375000 -0.283168 +v 0.692909 -0.385000 -0.287013 +v 0.692909 -0.365000 -0.287013 +v 0.615247 -0.375000 -0.411096 +v 0.623602 -0.385000 -0.416678 +v 0.623602 -0.365000 -0.416678 +v 0.523224 -0.375000 -0.523225 +v 0.530329 -0.385000 -0.530331 +v 0.530329 -0.365000 -0.530331 +v 0.411094 -0.375000 -0.615248 +v 0.416677 -0.385000 -0.623603 +v 0.416677 -0.365000 -0.623603 +v 0.283166 -0.375000 -0.683627 +v 0.287012 -0.385000 -0.692910 +v 0.287012 -0.365000 -0.692910 +v 0.144356 -0.375000 -0.725734 +v 0.146317 -0.385000 -0.735589 +v 0.146317 -0.365000 -0.735589 +v 0.000000 -0.375000 -0.739952 +v 0.000000 -0.385000 -0.750000 +v 0.000000 -0.365000 -0.750000 +vt 0.428686 0.858518 +vt 0.360113 0.837716 +vt 0.360113 0.837716 +vt 0.428686 0.858518 +vt 0.428686 0.858518 +vt 0.360113 0.837716 +vt 0.296916 0.803937 +vt 0.296916 0.803937 +vt 0.296916 0.803937 +vt 0.241523 0.758477 +vt 0.241523 0.758477 +vt 0.241523 0.758477 +vt 0.196063 0.703084 +vt 0.196063 0.703084 +vt 0.196063 0.703084 +vt 0.162284 0.639887 +vt 0.162284 0.639887 +vt 0.162284 0.639887 +vt 0.141482 0.571314 +vt 0.141482 0.571314 +vt 0.141482 0.571314 +vt 0.134459 0.500000 +vt 0.134459 0.500000 +vt 0.134459 0.500000 +vt 0.141482 0.428686 +vt 0.141482 0.428686 +vt 0.141482 0.428686 +vt 0.162284 0.360113 +vt 0.162284 0.360113 +vt 0.162284 0.360113 +vt 0.196063 0.296916 +vt 0.196063 0.296916 +vt 0.196063 0.296916 +vt 0.241523 0.241523 +vt 0.241523 0.241523 +vt 0.241523 0.241523 +vt 0.296916 0.196063 +vt 0.296916 0.196063 +vt 0.296916 0.196063 +vt 0.360113 0.162284 +vt 0.360113 0.162284 +vt 0.360113 0.162284 +vt 0.428686 0.141482 +vt 0.428686 0.141482 +vt 0.428686 0.141482 +vt 0.500000 0.134459 +vt 0.500000 0.134459 +vt 0.500000 0.134459 +vt 0.571314 0.141482 +vt 0.571314 0.141482 +vt 0.571314 0.141482 +vt 0.639887 0.162284 +vt 0.639887 0.162284 +vt 0.639887 0.162284 +vt 0.703084 0.196063 +vt 0.703084 0.196063 +vt 0.703084 0.196063 +vt 0.758477 0.241523 +vt 0.758477 0.241523 +vt 0.758477 0.241523 +vt 0.803937 0.296916 +vt 0.803937 0.296916 +vt 0.803937 0.296916 +vt 0.837716 0.360114 +vt 0.837716 0.360114 +vt 0.837716 0.360114 +vt 0.858518 0.428687 +vt 0.858518 0.428687 +vt 0.858518 0.428687 +vt 0.865541 0.500000 +vt 0.865541 0.500000 +vt 0.865541 0.500000 +vt 0.858518 0.571314 +vt 0.858518 0.571314 +vt 0.858518 0.571314 +vt 0.837716 0.639887 +vt 0.837716 0.639887 +vt 0.837716 0.639887 +vt 0.803936 0.703084 +vt 0.803936 0.703084 +vt 0.803936 0.703084 +vt 0.758477 0.758477 +vt 0.758477 0.758477 +vt 0.758477 0.758477 +vt 0.703084 0.803937 +vt 0.703084 0.803937 +vt 0.703084 0.803937 +vt 0.639886 0.837716 +vt 0.639886 0.837716 +vt 0.639886 0.837716 +vt 0.571313 0.858518 +vt 0.571313 0.858518 +vt 0.571313 0.858518 +vt 0.500000 0.865541 +vt 0.500000 0.865541 +vt 0.500000 0.865541 +vn 0.2053 -0.7071 0.6766 +vn 0.2053 0.7071 0.6766 +vn 0.3333 -0.7071 0.6236 +vn 0.3333 0.7071 0.6236 +vn 0.4486 -0.7071 0.5466 +vn 0.4486 0.7071 0.5466 +vn 0.5466 -0.7071 0.4486 +vn 0.5466 0.7071 0.4486 +vn 0.6236 -0.7071 0.3333 +vn 0.6236 0.7071 0.3333 +vn 0.6766 -0.7071 0.2053 +vn 0.6766 0.7071 0.2053 +vn 0.7037 -0.7071 0.0693 +vn 0.7037 0.7071 0.0693 +vn 0.7037 -0.7071 -0.0693 +vn 0.7037 0.7071 -0.0693 +vn 0.6767 -0.7071 -0.2053 +vn 0.6767 0.7071 -0.2053 +vn 0.6236 -0.7071 -0.3333 +vn 0.6236 0.7071 -0.3333 +vn 0.5466 -0.7071 -0.4486 +vn 0.5466 0.7071 -0.4486 +vn 0.4486 -0.7071 -0.5466 +vn 0.4486 0.7071 -0.5466 +vn 0.3333 -0.7071 -0.6236 +vn 0.3333 0.7071 -0.6236 +vn 0.2053 -0.7071 -0.6767 +vn 0.2053 0.7071 -0.6767 +vn 0.0693 -0.7071 -0.7037 +vn 0.0693 0.7071 -0.7037 +vn -0.0693 -0.7071 -0.7037 +vn -0.0693 0.7071 -0.7037 +vn -0.2053 -0.7071 -0.6767 +vn -0.2053 0.7071 -0.6767 +vn -0.3333 -0.7071 -0.6236 +vn -0.3333 0.7071 -0.6236 +vn -0.4486 -0.7071 -0.5466 +vn -0.4486 0.7071 -0.5466 +vn -0.5466 -0.7071 -0.4486 +vn -0.5466 0.7071 -0.4486 +vn -0.6236 -0.7071 -0.3333 +vn -0.6236 0.7071 -0.3333 +vn -0.6767 -0.7071 -0.2053 +vn -0.6767 0.7071 -0.2053 +vn -0.7037 -0.7071 -0.0693 +vn -0.7037 0.7071 -0.0693 +vn -0.7037 -0.7071 0.0693 +vn -0.7037 0.7071 0.0693 +vn -0.6767 -0.7071 0.2053 +vn -0.6767 0.7071 0.2053 +vn -0.6236 -0.7071 0.3333 +vn -0.6236 0.7071 0.3333 +vn -0.5466 -0.7071 0.4486 +vn -0.5466 0.7071 0.4486 +vn -0.4486 -0.7071 0.5466 +vn -0.4486 0.7071 0.5466 +vn -0.3333 -0.7071 0.6236 +vn -0.3333 0.7071 0.6236 +vn -0.2053 -0.7071 0.6767 +vn -0.2053 0.7071 0.6767 +vn -0.0693 -0.7071 0.7037 +vn -0.0693 0.7071 0.7037 +vn 0.0693 -0.7071 0.7037 +vn 0.0693 0.7071 0.7037 +usemtl mtrl/red +s off +f 1/1/1 2/2/1 3/3/1 4/4/1 +f 2/2/2 1/1/2 5/5/2 6/6/2 +f 2/2/3 7/7/3 8/8/3 3/3/3 +f 7/7/4 2/2/4 6/6/4 9/9/4 +f 7/7/5 10/10/5 11/11/5 8/8/5 +f 10/10/6 7/7/6 9/9/6 12/12/6 +f 10/10/7 13/13/7 14/14/7 11/11/7 +f 13/13/8 10/10/8 12/12/8 15/15/8 +f 13/13/9 16/16/9 17/17/9 14/14/9 +f 16/16/10 13/13/10 15/15/10 18/18/10 +f 16/16/11 19/19/11 20/20/11 17/17/11 +f 19/19/12 16/16/12 18/18/12 21/21/12 +f 19/19/13 22/22/13 23/23/13 20/20/13 +f 22/22/14 19/19/14 21/21/14 24/24/14 +f 22/22/15 25/25/15 26/26/15 23/23/15 +f 25/25/16 22/22/16 24/24/16 27/27/16 +f 25/25/17 28/28/17 29/29/17 26/26/17 +f 28/28/18 25/25/18 27/27/18 30/30/18 +f 28/28/19 31/31/19 32/32/19 29/29/19 +f 31/31/20 28/28/20 30/30/20 33/33/20 +f 31/31/21 34/34/21 35/35/21 32/32/21 +f 34/34/22 31/31/22 33/33/22 36/36/22 +f 34/34/23 37/37/23 38/38/23 35/35/23 +f 37/37/24 34/34/24 36/36/24 39/39/24 +f 37/37/25 40/40/25 41/41/25 38/38/25 +f 40/40/26 37/37/26 39/39/26 42/42/26 +f 40/40/27 43/43/27 44/44/27 41/41/27 +f 43/43/28 40/40/28 42/42/28 45/45/28 +f 43/43/29 46/46/29 47/47/29 44/44/29 +f 46/46/30 43/43/30 45/45/30 48/48/30 +f 46/46/31 49/49/31 50/50/31 47/47/31 +f 49/49/32 46/46/32 48/48/32 51/51/32 +f 49/49/33 52/52/33 53/53/33 50/50/33 +f 52/52/34 49/49/34 51/51/34 54/54/34 +f 52/52/35 55/55/35 56/56/35 53/53/35 +f 55/55/36 52/52/36 54/54/36 57/57/36 +f 55/55/37 58/58/37 59/59/37 56/56/37 +f 58/58/38 55/55/38 57/57/38 60/60/38 +f 58/58/39 61/61/39 62/62/39 59/59/39 +f 61/61/40 58/58/40 60/60/40 63/63/40 +f 61/61/41 64/64/41 65/65/41 62/62/41 +f 64/64/42 61/61/42 63/63/42 66/66/42 +f 64/64/43 67/67/43 68/68/43 65/65/43 +f 67/67/44 64/64/44 66/66/44 69/69/44 +f 67/67/45 70/70/45 71/71/45 68/68/45 +f 70/70/46 67/67/46 69/69/46 72/72/46 +f 70/70/47 73/73/47 74/74/47 71/71/47 +f 73/73/48 70/70/48 72/72/48 75/75/48 +f 73/73/49 76/76/49 77/77/49 74/74/49 +f 76/76/50 73/73/50 75/75/50 78/78/50 +f 76/76/51 79/79/51 80/80/51 77/77/51 +f 79/79/52 76/76/52 78/78/52 81/81/52 +f 79/79/53 82/82/53 83/83/53 80/80/53 +f 82/82/54 79/79/54 81/81/54 84/84/54 +f 82/82/55 85/85/55 86/86/55 83/83/55 +f 85/85/56 82/82/56 84/84/56 87/87/56 +f 85/85/57 88/88/57 89/89/57 86/86/57 +f 88/88/58 85/85/58 87/87/58 90/90/58 +f 88/88/59 91/91/59 92/92/59 89/89/59 +f 91/91/60 88/88/60 90/90/60 93/93/60 +f 91/91/61 94/94/61 95/95/61 92/92/61 +f 94/94/62 91/91/62 93/93/62 96/96/62 +f 94/94/63 1/1/63 4/4/63 95/95/63 +f 1/1/64 94/94/64 96/96/64 5/5/64 diff --git a/tools/trenchbroom/games/Neverball/assets/__tb_info_player_start.obj b/tools/trenchbroom/games/Neverball/assets/__tb_info_player_start.obj new file mode 100644 index 0000000..8d9a06a --- /dev/null +++ b/tools/trenchbroom/games/Neverball/assets/__tb_info_player_start.obj @@ -0,0 +1,2150 @@ +# Blender v2.79 (sub 0) OBJ File: '__tb_info_player_start.blend' +# www.blender.org +o Sphere +v 0.000000 0.120196 -0.048773 +v 0.000000 0.105970 -0.095671 +v 0.000000 0.082867 -0.138893 +v 0.000000 0.051777 -0.176777 +v 0.000000 0.013893 -0.207867 +v 0.000000 -0.029329 -0.230970 +v 0.000000 -0.076227 -0.245196 +v 0.000000 -0.125000 -0.250000 +v 0.000000 -0.173773 -0.245196 +v 0.000000 -0.332867 -0.138893 +v 0.009515 0.120196 -0.047835 +v 0.018664 0.105970 -0.093833 +v 0.027097 0.082867 -0.136224 +v 0.034487 0.051777 -0.173380 +v 0.040553 0.013893 -0.203873 +v 0.045060 -0.029329 -0.226532 +v 0.047835 -0.076227 -0.240485 +v 0.048773 -0.125000 -0.245196 +v 0.047835 -0.173773 -0.240485 +v 0.045060 -0.220671 -0.226532 +v 0.040553 -0.263893 -0.203873 +v 0.034487 -0.301777 -0.173380 +v 0.027097 -0.332867 -0.136224 +v 0.018664 -0.355970 -0.093833 +v 0.009515 -0.370196 -0.047835 +v 0.018664 0.120196 -0.045060 +v 0.036612 0.105970 -0.088388 +v 0.053152 0.082867 -0.128320 +v 0.067650 0.051777 -0.163320 +v 0.079547 0.013893 -0.192044 +v 0.088388 -0.029329 -0.213388 +v 0.093833 -0.076227 -0.226532 +v 0.095671 -0.125000 -0.230970 +v 0.093833 -0.173773 -0.226532 +v 0.088388 -0.220671 -0.213388 +v 0.079547 -0.263893 -0.192044 +v 0.067650 -0.301777 -0.163320 +v 0.053152 -0.332867 -0.128320 +v 0.036612 -0.355970 -0.088388 +v 0.018664 -0.370196 -0.045060 +v 0.027097 0.120196 -0.040553 +v 0.053152 0.105970 -0.079547 +v 0.077165 0.082867 -0.115485 +v 0.098212 0.051777 -0.146984 +v 0.115485 0.013893 -0.172835 +v 0.128320 -0.029329 -0.192044 +v 0.136224 -0.076227 -0.203873 +v 0.138893 -0.125000 -0.207867 +v 0.136224 -0.173773 -0.203873 +v 0.128320 -0.220671 -0.192044 +v 0.115485 -0.263893 -0.172835 +v 0.098212 -0.301777 -0.146984 +v 0.077165 -0.332867 -0.115485 +v 0.053152 -0.355970 -0.079547 +v 0.027097 -0.370196 -0.040553 +v 0.034487 0.120196 -0.034487 +v 0.067650 0.105970 -0.067649 +v 0.098212 0.082867 -0.098212 +v 0.125000 0.051777 -0.125000 +v 0.146985 0.013893 -0.146984 +v 0.163320 -0.029329 -0.163320 +v 0.173380 -0.076227 -0.173380 +v 0.176777 -0.125000 -0.176777 +v 0.173380 -0.173773 -0.173380 +v 0.163320 -0.220671 -0.163320 +v 0.146985 -0.263893 -0.146984 +v 0.125000 -0.301777 -0.125000 +v 0.098212 -0.332867 -0.098212 +v 0.067650 -0.355970 -0.067649 +v 0.034487 -0.370196 -0.034487 +v 0.040553 0.120196 -0.027097 +v 0.079547 0.105970 -0.053152 +v 0.115485 0.082867 -0.077165 +v 0.146985 0.051777 -0.098212 +v 0.172835 0.013893 -0.115485 +v 0.192044 -0.029329 -0.128320 +v 0.203873 -0.076227 -0.136224 +v 0.207867 -0.125000 -0.138893 +v 0.203873 -0.173773 -0.136224 +v 0.192044 -0.220671 -0.128320 +v 0.172835 -0.263893 -0.115485 +v 0.146985 -0.301777 -0.098212 +v 0.115485 -0.332867 -0.077165 +v 0.079547 -0.355970 -0.053152 +v 0.040553 -0.370196 -0.027097 +v 0.045060 0.120196 -0.018664 +v 0.088388 0.105970 -0.036612 +v 0.128320 0.082867 -0.053152 +v 0.163320 0.051777 -0.067649 +v 0.192044 0.013893 -0.079547 +v 0.213388 -0.029329 -0.088388 +v 0.226532 -0.076227 -0.093832 +v 0.230970 -0.125000 -0.095671 +v 0.226532 -0.173773 -0.093832 +v 0.213388 -0.220671 -0.088388 +v 0.192044 -0.263893 -0.079547 +v 0.163320 -0.301777 -0.067649 +v 0.128320 -0.332867 -0.053152 +v 0.088388 -0.355970 -0.036612 +v 0.045060 -0.370196 -0.018664 +v 0.047836 0.120196 -0.009515 +v 0.093833 0.105970 -0.018664 +v 0.136224 0.082867 -0.027097 +v 0.173380 0.051777 -0.034487 +v 0.203873 0.013893 -0.040553 +v 0.226532 -0.029329 -0.045060 +v 0.240485 -0.076227 -0.047835 +v 0.245196 -0.125000 -0.048772 +v 0.240485 -0.173773 -0.047835 +v 0.226532 -0.220671 -0.045060 +v 0.203873 -0.263893 -0.040553 +v 0.173380 -0.301777 -0.034487 +v 0.136224 -0.332867 -0.027097 +v 0.093833 -0.355970 -0.018664 +v 0.047835 -0.370196 -0.009515 +v 0.048773 0.120196 0.000000 +v 0.095671 0.105970 0.000000 +v 0.138893 0.082867 0.000000 +v 0.176777 0.051777 0.000000 +v 0.207867 0.013893 0.000000 +v 0.230970 -0.029329 0.000000 +v 0.245196 -0.076227 0.000000 +v 0.250000 -0.125000 0.000000 +v 0.245196 -0.173773 0.000000 +v 0.230970 -0.220671 0.000000 +v 0.207867 -0.263893 0.000000 +v 0.176777 -0.301777 0.000000 +v 0.138893 -0.332867 0.000000 +v 0.095671 -0.355970 0.000000 +v 0.048773 -0.370196 0.000000 +v 0.047835 0.120196 0.009515 +v 0.093833 0.105970 0.018665 +v 0.136224 0.082867 0.027097 +v 0.173380 0.051777 0.034488 +v 0.203873 0.013893 0.040553 +v 0.226532 -0.029329 0.045060 +v 0.240485 -0.076227 0.047836 +v 0.245196 -0.125000 0.048773 +v 0.240485 -0.173773 0.047836 +v 0.226532 -0.220671 0.045060 +v 0.203873 -0.263893 0.040553 +v 0.173380 -0.301777 0.034488 +v 0.136224 -0.332867 0.027097 +v 0.093833 -0.355970 0.018665 +v 0.047835 -0.370196 0.009515 +v 0.045060 0.120196 0.018665 +v 0.088388 0.105970 0.036612 +v 0.128320 0.082867 0.053152 +v 0.163320 0.051777 0.067650 +v 0.192044 0.013893 0.079548 +v 0.213388 -0.029329 0.088388 +v 0.226532 -0.076227 0.093833 +v 0.230970 -0.125000 0.095671 +v 0.226532 -0.173773 0.093833 +v 0.213388 -0.220671 0.088388 +v 0.192044 -0.263893 0.079548 +v 0.163320 -0.301777 0.067650 +v 0.128320 -0.332867 0.053152 +v 0.088388 -0.355970 0.036612 +v 0.045060 -0.370196 0.018665 +v 0.040553 0.120196 0.027097 +v 0.079547 0.105970 0.053152 +v 0.115485 0.082867 0.077165 +v 0.146984 0.051777 0.098212 +v 0.172835 0.013893 0.115485 +v 0.192044 -0.029329 0.128320 +v 0.203873 -0.076227 0.136224 +v 0.207867 -0.125000 0.138893 +v 0.203873 -0.173773 0.136224 +v 0.192044 -0.220671 0.128320 +v 0.172835 -0.263893 0.115485 +v 0.146984 -0.301777 0.098212 +v 0.115485 -0.332867 0.077165 +v 0.079547 -0.355970 0.053152 +v 0.040553 -0.370196 0.027097 +v 0.034487 0.120196 0.034488 +v 0.067650 0.105970 0.067650 +v 0.098212 0.082867 0.098212 +v 0.125000 0.051777 0.125000 +v 0.146984 0.013893 0.146985 +v 0.163320 -0.029329 0.163320 +v 0.173380 -0.076227 0.173380 +v 0.176777 -0.125000 0.176777 +v 0.173380 -0.173773 0.173380 +v 0.163320 -0.220671 0.163320 +v 0.146984 -0.263893 0.146985 +v 0.125000 -0.301777 0.125000 +v 0.098212 -0.332867 0.098212 +v 0.067650 -0.355970 0.067650 +v 0.034487 -0.370196 0.034488 +v 0.027097 0.120196 0.040553 +v 0.053152 0.105970 0.079548 +v 0.077165 0.082867 0.115485 +v 0.098212 0.051777 0.146985 +v 0.115485 0.013893 0.172836 +v 0.128320 -0.029329 0.192045 +v 0.136224 -0.076227 0.203873 +v 0.138893 -0.125000 0.207868 +v 0.136224 -0.173773 0.203873 +v 0.128320 -0.220671 0.192045 +v 0.115485 -0.263893 0.172836 +v 0.098212 -0.301777 0.146985 +v 0.077165 -0.332867 0.115485 +v 0.053152 -0.355970 0.079547 +v 0.027097 -0.370196 0.040553 +v 0.000000 -0.375000 0.000000 +v 0.018664 0.120196 0.045060 +v 0.036612 0.105970 0.088388 +v 0.053152 0.082867 0.128320 +v 0.067650 0.051777 0.163320 +v 0.079547 0.013893 0.192045 +v 0.088388 -0.029329 0.213388 +v 0.093833 -0.076227 0.226532 +v 0.095671 -0.125000 0.230970 +v 0.093833 -0.173773 0.226532 +v 0.088388 -0.220671 0.213388 +v 0.079547 -0.263893 0.192045 +v 0.067650 -0.301777 0.163320 +v 0.053152 -0.332867 0.128320 +v 0.036612 -0.355970 0.088388 +v 0.018664 -0.370196 0.045060 +v 0.009515 0.120196 0.047836 +v 0.018664 0.105970 0.093833 +v 0.027097 0.082867 0.136224 +v 0.034487 0.051777 0.173380 +v 0.040553 0.013893 0.203873 +v 0.045060 -0.029329 0.226532 +v 0.047835 -0.076227 0.240485 +v 0.048773 -0.125000 0.245196 +v 0.047835 -0.173773 0.240485 +v 0.045060 -0.220671 0.226532 +v 0.040553 -0.263893 0.203873 +v 0.034487 -0.301777 0.173380 +v 0.027097 -0.332867 0.136224 +v 0.018664 -0.355970 0.093833 +v 0.009515 -0.370196 0.047836 +v -0.000000 0.120196 0.048773 +v 0.000000 0.105970 0.095671 +v 0.000000 0.082867 0.138893 +v -0.000000 0.051777 0.176777 +v -0.000000 0.013893 0.207867 +v 0.000000 -0.029329 0.230970 +v -0.000000 -0.076227 0.245196 +v -0.000000 -0.125000 0.250000 +v -0.000000 -0.173773 0.245196 +v 0.000000 -0.220671 0.230970 +v -0.000000 -0.263893 0.207867 +v -0.000000 -0.301777 0.176777 +v -0.000000 -0.332867 0.138893 +v 0.000000 -0.355970 0.095671 +v 0.000000 -0.370196 0.048773 +v -0.009515 0.120196 0.047836 +v -0.018664 0.105970 0.093833 +v -0.027097 0.082867 0.136224 +v -0.034487 0.051777 0.173380 +v -0.040553 0.013893 0.203873 +v -0.045060 -0.029329 0.226532 +v -0.047835 -0.076227 0.240485 +v -0.048773 -0.125000 0.245196 +v -0.047835 -0.173773 0.240485 +v -0.045060 -0.220671 0.226532 +v -0.040553 -0.263893 0.203873 +v -0.034487 -0.301777 0.173380 +v -0.027097 -0.332867 0.136224 +v -0.018664 -0.355970 0.093833 +v -0.009515 -0.370196 0.047836 +v -0.018664 0.120196 0.045060 +v -0.036612 0.105970 0.088388 +v -0.053152 0.082867 0.128320 +v -0.067650 0.051777 0.163320 +v -0.079547 0.013893 0.192044 +v -0.088388 -0.029329 0.213388 +v -0.093833 -0.076227 0.226532 +v -0.095671 -0.125000 0.230970 +v -0.093833 -0.173773 0.226532 +v -0.088388 -0.220671 0.213388 +v -0.079547 -0.263893 0.192044 +v -0.067650 -0.301777 0.163320 +v -0.053152 -0.332867 0.128320 +v -0.036612 -0.355970 0.088388 +v -0.018664 -0.370196 0.045060 +v -0.027097 0.120196 0.040553 +v -0.053152 0.105970 0.079547 +v -0.077165 0.082867 0.115485 +v -0.098212 0.051777 0.146985 +v -0.115485 0.013893 0.172835 +v -0.128320 -0.029329 0.192045 +v -0.136224 -0.076227 0.203873 +v -0.138893 -0.125000 0.207867 +v -0.136224 -0.173773 0.203873 +v -0.128320 -0.220671 0.192045 +v -0.115485 -0.263893 0.172835 +v -0.098212 -0.301777 0.146985 +v -0.077165 -0.332867 0.115485 +v -0.053152 -0.355970 0.079547 +v -0.027097 -0.370196 0.040553 +v -0.000000 0.125000 0.000000 +v -0.034487 0.120196 0.034488 +v -0.067650 0.105970 0.067650 +v -0.098212 0.082867 0.098212 +v -0.125000 0.051777 0.125000 +v -0.146984 0.013893 0.146984 +v -0.163320 -0.029329 0.163320 +v -0.173380 -0.076227 0.173380 +v -0.176777 -0.125000 0.176777 +v -0.173380 -0.173773 0.173380 +v -0.163320 -0.220671 0.163320 +v -0.146984 -0.263893 0.146984 +v -0.125000 -0.301777 0.125000 +v -0.098212 -0.332867 0.098212 +v -0.067649 -0.355970 0.067650 +v -0.034487 -0.370196 0.034487 +v -0.040553 0.120196 0.027097 +v -0.079547 0.105970 0.053152 +v -0.115485 0.082867 0.077165 +v -0.146984 0.051777 0.098212 +v -0.172835 0.013893 0.115485 +v -0.192044 -0.029329 0.128320 +v -0.203873 -0.076227 0.136224 +v -0.207867 -0.125000 0.138893 +v -0.203873 -0.173773 0.136224 +v -0.192044 -0.220671 0.128320 +v -0.172835 -0.263893 0.115485 +v -0.146984 -0.301777 0.098212 +v -0.115485 -0.332867 0.077165 +v -0.079547 -0.355970 0.053152 +v -0.040553 -0.370196 0.027097 +v -0.045060 0.120196 0.018665 +v -0.088388 0.105970 0.036612 +v -0.128320 0.082867 0.053152 +v -0.163320 0.051777 0.067650 +v -0.192044 0.013893 0.079547 +v -0.213388 -0.029329 0.088388 +v -0.226532 -0.076227 0.093833 +v -0.230970 -0.125000 0.095671 +v -0.226532 -0.173773 0.093833 +v -0.213388 -0.220671 0.088388 +v -0.192044 -0.263893 0.079547 +v -0.163320 -0.301777 0.067650 +v -0.128320 -0.332867 0.053152 +v -0.088388 -0.355970 0.036612 +v -0.045060 -0.370196 0.018665 +v -0.047835 0.120196 0.009515 +v -0.093833 0.105970 0.018665 +v -0.136224 0.082867 0.027097 +v -0.173380 0.051777 0.034487 +v -0.203873 0.013893 0.040553 +v -0.226532 -0.029329 0.045060 +v -0.240485 -0.076227 0.047835 +v -0.245196 -0.125000 0.048773 +v -0.240485 -0.173773 0.047835 +v -0.226532 -0.220671 0.045060 +v -0.203873 -0.263893 0.040553 +v -0.173380 -0.301777 0.034487 +v -0.136224 -0.332867 0.027097 +v -0.093833 -0.355970 0.018665 +v -0.047835 -0.370196 0.009515 +v -0.048773 0.120196 0.000000 +v -0.095671 0.105970 0.000000 +v -0.138893 0.082867 0.000000 +v -0.176777 0.051777 0.000000 +v -0.207867 0.013893 0.000000 +v -0.230970 -0.029329 0.000000 +v -0.245196 -0.076227 0.000000 +v -0.250000 -0.125000 0.000000 +v -0.245196 -0.173773 0.000000 +v -0.230970 -0.220671 0.000000 +v -0.207867 -0.263893 0.000000 +v -0.176777 -0.301777 0.000000 +v -0.138893 -0.332867 0.000000 +v -0.095671 -0.355970 0.000000 +v -0.048773 -0.370196 0.000000 +v -0.047835 0.120196 -0.009515 +v -0.093833 0.105970 -0.018664 +v -0.136224 0.082867 -0.027097 +v -0.173380 0.051777 -0.034487 +v -0.203873 0.013893 -0.040553 +v -0.226532 -0.029329 -0.045060 +v -0.240485 -0.076227 -0.047835 +v -0.245196 -0.125000 -0.048773 +v -0.240485 -0.173773 -0.047835 +v -0.226532 -0.220671 -0.045060 +v -0.203873 -0.263893 -0.040553 +v -0.173380 -0.301777 -0.034487 +v -0.136224 -0.332867 -0.027097 +v -0.093833 -0.355970 -0.018664 +v -0.047835 -0.370196 -0.009515 +v -0.045060 0.120196 -0.018664 +v -0.088388 0.105970 -0.036612 +v -0.128320 0.082867 -0.053152 +v -0.163320 0.051777 -0.067649 +v -0.192044 0.013893 -0.079547 +v -0.213388 -0.029329 -0.088388 +v -0.226532 -0.076227 -0.093832 +v -0.230970 -0.125000 -0.095671 +v -0.226532 -0.173773 -0.093832 +v -0.213388 -0.220671 -0.088388 +v -0.192044 -0.263893 -0.079547 +v -0.163320 -0.301777 -0.067649 +v -0.128320 -0.332867 -0.053152 +v -0.088388 -0.355970 -0.036612 +v -0.045060 -0.370196 -0.018664 +v -0.040553 0.120196 -0.027097 +v -0.079547 0.105970 -0.053152 +v -0.115485 0.082867 -0.077164 +v -0.146984 0.051777 -0.098212 +v -0.172835 0.013893 -0.115485 +v -0.192044 -0.029329 -0.128320 +v -0.203873 -0.076227 -0.136224 +v -0.207867 -0.125000 -0.138892 +v -0.203873 -0.173773 -0.136224 +v -0.192044 -0.220671 -0.128320 +v -0.172835 -0.263893 -0.115485 +v -0.146984 -0.301777 -0.098212 +v -0.115485 -0.332867 -0.077164 +v -0.079547 -0.355970 -0.053152 +v -0.040553 -0.370196 -0.027097 +v -0.034487 0.120196 -0.034487 +v -0.067649 0.105970 -0.067649 +v -0.098212 0.082867 -0.098212 +v -0.125000 0.051777 -0.125000 +v -0.146984 0.013893 -0.146984 +v -0.163320 -0.029329 -0.163320 +v -0.173380 -0.076227 -0.173380 +v -0.176777 -0.125000 -0.176777 +v -0.173380 -0.173773 -0.173380 +v -0.163320 -0.220671 -0.163320 +v -0.146984 -0.263893 -0.146984 +v -0.125000 -0.301777 -0.125000 +v -0.098212 -0.332867 -0.098212 +v -0.067649 -0.355970 -0.067649 +v -0.034487 -0.370196 -0.034487 +v -0.027097 0.120196 -0.040553 +v -0.053152 0.105970 -0.079547 +v -0.077165 0.082867 -0.115485 +v -0.098212 0.051777 -0.146984 +v -0.115485 0.013893 -0.172835 +v -0.128320 -0.029329 -0.192044 +v -0.136224 -0.076227 -0.203873 +v -0.138892 -0.125000 -0.207867 +v -0.136224 -0.173773 -0.203873 +v -0.128320 -0.220671 -0.192044 +v -0.115485 -0.263893 -0.172835 +v -0.098212 -0.301777 -0.146984 +v -0.077165 -0.332867 -0.115485 +v -0.053152 -0.355970 -0.079547 +v -0.027097 -0.370196 -0.040553 +v -0.018664 0.120196 -0.045060 +v -0.036612 0.105970 -0.088388 +v -0.053152 0.082867 -0.128320 +v -0.067649 0.051777 -0.163320 +v -0.079547 0.013893 -0.192044 +v -0.088388 -0.029329 -0.213388 +v -0.093832 -0.076227 -0.226532 +v -0.095671 -0.125000 -0.230970 +v -0.093832 -0.173773 -0.226532 +v -0.088388 -0.220671 -0.213388 +v -0.079547 -0.263893 -0.192044 +v -0.067649 -0.301777 -0.163320 +v -0.053152 -0.332867 -0.128320 +v -0.036612 -0.355970 -0.088388 +v -0.018664 -0.370196 -0.045060 +v -0.009515 0.120196 -0.047835 +v -0.018664 0.105970 -0.093832 +v -0.027097 0.082867 -0.136224 +v -0.034487 0.051777 -0.173380 +v -0.040553 0.013893 -0.203873 +v -0.045060 -0.029329 -0.226532 +v -0.047835 -0.076227 -0.240485 +v -0.048772 -0.125000 -0.245196 +v -0.047835 -0.173773 -0.240485 +v -0.045060 -0.220671 -0.226532 +v -0.040553 -0.263893 -0.203873 +v -0.034487 -0.301777 -0.173380 +v -0.027097 -0.332867 -0.136224 +v -0.018664 -0.355970 -0.093832 +v -0.009515 -0.370196 -0.047835 +v 0.000000 -0.220671 -0.230970 +v 0.000000 -0.263893 -0.207867 +v 0.000000 -0.301777 -0.176777 +v 0.000000 -0.355970 -0.095671 +v 0.000000 -0.370196 -0.048772 +v -0.037254 -0.150000 -0.570000 +v 0.037254 -0.150000 -0.570000 +v -0.120000 -0.150000 -0.570000 +v 0.120000 -0.150000 -0.570000 +v 0.000000 -0.150000 -0.700000 +v -0.037254 -0.150000 -0.300000 +v 0.037254 -0.150000 -0.300000 +v 0.023091 -0.084714 -0.574296 +v -0.091322 -0.084714 -0.574296 +v -0.023091 -0.084714 -0.574296 +v 0.091322 -0.084714 -0.574296 +v 0.000000 -0.084714 -0.680121 +v -0.023091 -0.084714 -0.304013 +v 0.023091 -0.084714 -0.304013 +v -0.120000 -0.100000 -0.570000 +v -0.037254 -0.100000 -0.570000 +v 0.037254 -0.100000 -0.570000 +v 0.120000 -0.100000 -0.570000 +v 0.000000 -0.100000 -0.700000 +v -0.037254 -0.100000 -0.300000 +v 0.037254 -0.100000 -0.300000 +vt 0.668772 0.339905 +vt 0.689230 0.360743 +vt 0.669184 0.377746 +vt 0.651681 0.356229 +vt 0.646681 0.320659 +vt 0.633008 0.335578 +vt 0.622926 0.303143 +vt 0.612891 0.315762 +vt 0.597548 0.287432 +vt 0.591132 0.296771 +vt 0.570644 0.273504 +vt 0.567617 0.278601 +vt 0.542292 0.261250 +vt 0.708194 0.382963 +vt 0.726005 0.406260 +vt 0.702401 0.423755 +vt 0.685896 0.400205 +vt 0.663172 0.415515 +vt 0.648629 0.392409 +vt 0.633758 0.370044 +vt 0.618149 0.348117 +vt 0.601457 0.326404 +vt 0.583389 0.304743 +vt 0.563718 0.283032 +vt 0.677930 0.439801 +vt 0.588867 0.335092 +vt 0.574555 0.311248 +vt 0.559087 0.286667 +vt 0.652447 0.453972 +vt 0.639692 0.428795 +vt 0.627341 0.404858 +vt 0.614973 0.381555 +vt 0.602248 0.358424 +vt 0.605219 0.415133 +vt 0.595309 0.390853 +vt 0.585400 0.366570 +vt 0.575302 0.341820 +vt 0.564843 0.316200 +vt 0.553878 0.289397 +vt 0.625970 0.466029 +vt 0.615350 0.439958 +vt 0.554450 0.319516 +vt 0.548253 0.291138 +vt 0.598611 0.475863 +vt 0.590142 0.448972 +vt 0.582222 0.423250 +vt 0.574753 0.397969 +vt 0.567667 0.372561 +vt 0.560912 0.346549 +vt 0.558307 0.429239 +vt 0.553277 0.402895 +vt 0.549089 0.376349 +vt 0.545827 0.349198 +vt 0.543571 0.321107 +vt 0.542388 0.291828 +vt 0.570531 0.483497 +vt 0.564093 0.455881 +vt 0.532418 0.320875 +vt 0.536469 0.291426 +vt 0.541920 0.489120 +vt 0.537178 0.460846 +vt 0.533366 0.433155 +vt 0.530795 0.405581 +vt 0.529677 0.377815 +vt 0.530176 0.349635 +vt 0.507124 0.405903 +vt 0.509417 0.376745 +vt 0.514114 0.347662 +vt 0.521233 0.318712 +vt 0.530693 0.289920 +vt 0.512983 0.493192 +vt 0.509189 0.464218 +vt 0.507124 0.435075 +vt 0.478275 0.389352 +vt 0.458023 0.410549 +vt 0.437837 0.390872 +vt 0.456847 0.369458 +vt 0.305590 0.503188 +vt 0.274071 0.511469 +vt 0.303203 0.497438 +vt 0.335155 0.492703 +vt 0.329861 0.482249 +vt 0.362996 0.480142 +vt 0.354467 0.466015 +vt 0.389163 0.465525 +vt 0.377271 0.448753 +vt 0.413677 0.448937 +vt 0.398545 0.430479 +vt 0.436588 0.430533 +vt 0.418601 0.411192 +vt 0.363990 0.434240 +vt 0.382403 0.414428 +vt 0.399978 0.394108 +vt 0.417176 0.373033 +vt 0.434588 0.350856 +vt 0.299830 0.492271 +vt 0.323071 0.473038 +vt 0.344338 0.453729 +vt 0.295606 0.487831 +vt 0.315021 0.465181 +vt 0.332858 0.443260 +vt 0.349473 0.421814 +vt 0.365227 0.400541 +vt 0.380492 0.379094 +vt 0.395678 0.357064 +vt 0.411284 0.333923 +vt 0.346997 0.388694 +vt 0.360029 0.366073 +vt 0.373209 0.343012 +vt 0.386906 0.318870 +vt 0.290678 0.484238 +vt 0.305914 0.458770 +vt 0.320206 0.434610 +vt 0.333813 0.411389 +vt 0.285201 0.481590 +vt 0.295937 0.453893 +vt 0.306517 0.427812 +vt 0.317063 0.402941 +vt 0.327692 0.378832 +vt 0.338534 0.355000 +vt 0.349744 0.330884 +vt 0.361527 0.305791 +vt 0.307269 0.370937 +vt 0.315958 0.345818 +vt 0.325296 0.320623 +vt 0.335283 0.294666 +vt 0.279342 0.479964 +vt 0.285267 0.450647 +vt 0.291900 0.422942 +vt 0.299242 0.396501 +vt 0.274090 0.449137 +vt 0.276456 0.420125 +vt 0.280338 0.392161 +vt 0.285630 0.365021 +vt 0.292195 0.338439 +vt 0.299855 0.312058 +vt 0.308359 0.285328 +vt 0.273275 0.479414 +vt 0.266993 0.332732 +vt 0.273284 0.304833 +vt 0.280980 0.277371 +vt 0.267187 0.479974 +vt 0.262617 0.449483 +vt 0.260296 0.419552 +vt 0.260296 0.390103 +vt 0.262575 0.361154 +vt 0.564347 0.675320 +vt 0.543898 0.654488 +vt 0.563946 0.637492 +vt 0.581435 0.658999 +vt 0.586437 0.694569 +vt 0.600112 0.679650 +vt 0.610192 0.712088 +vt 0.620229 0.699470 +vt 0.635570 0.727802 +vt 0.641987 0.718463 +vt 0.662473 0.741731 +vt 0.665500 0.736635 +vt 0.690823 0.753987 +vt 0.524935 0.632265 +vt 0.507124 0.608964 +vt 0.530732 0.591469 +vt 0.547237 0.615024 +vt 0.649731 0.710492 +vt 0.669399 0.732204 +vt 0.555208 0.575421 +vt 0.569968 0.599712 +vt 0.584515 0.622824 +vt 0.599366 0.645177 +vt 0.614975 0.667111 +vt 0.631664 0.688828 +vt 0.605807 0.610369 +vt 0.618159 0.633668 +vt 0.630879 0.656805 +vt 0.644257 0.680142 +vt 0.658565 0.703988 +vt 0.674030 0.728570 +vt 0.580696 0.561249 +vt 0.593452 0.586430 +vt 0.668278 0.699037 +vt 0.679240 0.725841 +vt 0.607176 0.549193 +vt 0.617796 0.575265 +vt 0.627928 0.600091 +vt 0.637829 0.624374 +vt 0.647731 0.648663 +vt 0.657823 0.673416 +vt 0.658390 0.617269 +vt 0.665465 0.642677 +vt 0.672213 0.668690 +vt 0.678671 0.695722 +vt 0.684864 0.724100 +vt 0.634536 0.539361 +vt 0.643004 0.566251 +vt 0.650928 0.591972 +vt 0.690729 0.723410 +vt 0.662613 0.531730 +vt 0.669050 0.559341 +vt 0.674839 0.585978 +vt 0.679866 0.612354 +vt 0.684042 0.638896 +vt 0.687298 0.666044 +vt 0.689549 0.694133 +vt 0.703451 0.637435 +vt 0.702946 0.665609 +vt 0.700701 0.694366 +vt 0.696648 0.723813 +vt 0.691218 0.526109 +vt 0.695958 0.554375 +vt 0.699773 0.582056 +vt 0.702344 0.609678 +vt 0.720145 0.522040 +vt 0.723936 0.551005 +vt 0.725999 0.580136 +vt 0.725999 0.609363 +vt 0.723704 0.638508 +vt 0.719005 0.667584 +vt 0.711884 0.696530 +vt 0.702423 0.725319 +vt 0.189946 0.171162 +vt 0.167327 0.188875 +vt 0.152666 0.170621 +vt 0.172639 0.151935 +vt 0.211232 0.152027 +vt 0.191935 0.132356 +vt 0.231447 0.131881 +vt 0.211109 0.111861 +vt 0.061469 0.242777 +vt 0.030595 0.252304 +vt 0.058935 0.237166 +vt 0.090334 0.231872 +vt 0.084975 0.221653 +vt 0.117564 0.219306 +vt 0.109119 0.205449 +vt 0.143219 0.204965 +vt 0.131596 0.188451 +vt 0.055439 0.232139 +vt 0.078137 0.212633 +vt 0.099071 0.193344 +vt 0.118548 0.174069 +vt 0.136924 0.154618 +vt 0.154589 0.134786 +vt 0.172025 0.114329 +vt 0.189792 0.092919 +vt 0.120057 0.140650 +vt 0.135553 0.119561 +vt 0.151126 0.098002 +vt 0.167257 0.075451 +vt 0.051111 0.227840 +vt 0.070041 0.204930 +vt 0.087646 0.182986 +vt 0.104208 0.161672 +vt 0.060878 0.198647 +vt 0.075006 0.174391 +vt 0.088649 0.151197 +vt 0.102027 0.128623 +vt 0.115399 0.106210 +vt 0.129082 0.083446 +vt 0.143445 0.059697 +vt 0.046092 0.224391 +vt 0.094059 0.094708 +vt 0.105856 0.070698 +vt 0.118411 0.045782 +vt 0.040536 0.221892 +vt 0.050824 0.193883 +vt 0.061274 0.167614 +vt 0.071908 0.142643 +vt 0.082798 0.118505 +vt 0.046550 0.162751 +vt 0.053993 0.136069 +vt 0.062309 0.110309 +vt 0.071461 0.085035 +vt 0.081442 0.059742 +vt 0.092269 0.033725 +vt 0.034607 0.220421 +vt 0.040051 0.190748 +vt 0.055798 0.050439 +vt 0.065182 0.023397 +vt 0.028480 0.220039 +vt 0.028743 0.189363 +vt 0.030929 0.159948 +vt 0.034881 0.131594 +vt 0.040449 0.104080 +vt 0.047477 0.077142 +vt 0.014424 0.159388 +vt 0.014424 0.129394 +vt 0.016940 0.099886 +vt 0.021811 0.070899 +vt 0.028776 0.042442 +vt 0.037375 0.014424 +vt 0.022300 0.220775 +vt 0.017030 0.189838 +vt 0.689219 0.829922 +vt 0.689219 0.782836 +vt 0.763195 0.851121 +vt 0.689219 0.919407 +vt 0.689219 0.872320 +vt 0.535576 0.872320 +vt 0.535576 0.829922 +vt 0.237255 0.957123 +vt 0.390897 0.957123 +vt 0.390897 0.985575 +vt 0.237255 0.985575 +vt 0.507124 0.872320 +vt 0.507124 0.829922 +vt 0.538658 0.957123 +vt 0.639333 0.957123 +vt 0.639333 0.985576 +vt 0.538658 0.985576 +vt 0.686420 0.957123 +vt 0.840062 0.957123 +vt 0.840062 0.985576 +vt 0.686419 0.985576 +vt 0.437984 0.957123 +vt 0.437984 0.985576 +vt 0.248845 0.847133 +vt 0.411617 0.845477 +vt 0.411848 0.870664 +vt 0.249009 0.871431 +vt 0.415761 0.905432 +vt 0.414790 0.810674 +vt 0.462399 0.857511 +vt 0.409098 0.928275 +vt 0.400713 0.883090 +vt 0.400273 0.833288 +vt 0.407635 0.788021 +vt 0.478275 0.857323 +vt 0.237255 0.883057 +vt 0.237255 0.835486 +vt 0.389163 0.202579 +vt 0.362996 0.217196 +vt 0.354467 0.203069 +vt 0.377271 0.185807 +vt 0.413677 0.185991 +vt 0.398545 0.167533 +vt 0.436588 0.167587 +vt 0.418601 0.148246 +vt 0.458023 0.147603 +vt 0.437837 0.127926 +vt 0.478275 0.126406 +vt 0.456847 0.106512 +vt 0.305589 0.240241 +vt 0.274071 0.248522 +vt 0.303203 0.234492 +vt 0.335155 0.229756 +vt 0.329861 0.219303 +vt 0.323071 0.210092 +vt 0.344338 0.190783 +vt 0.363989 0.171294 +vt 0.382403 0.151482 +vt 0.399978 0.131162 +vt 0.417177 0.110087 +vt 0.434588 0.087911 +vt 0.299830 0.229324 +vt 0.380492 0.116148 +vt 0.395679 0.094118 +vt 0.411285 0.070977 +vt 0.295606 0.224884 +vt 0.315020 0.202234 +vt 0.332858 0.180314 +vt 0.349473 0.158868 +vt 0.365227 0.137595 +vt 0.305914 0.195823 +vt 0.320206 0.171664 +vt 0.333813 0.148443 +vt 0.346997 0.125748 +vt 0.360029 0.103127 +vt 0.373209 0.080066 +vt 0.386907 0.055924 +vt 0.290677 0.221292 +vt 0.338534 0.092053 +vt 0.349744 0.067938 +vt 0.361527 0.042845 +vt 0.285201 0.218644 +vt 0.295936 0.190947 +vt 0.306517 0.164866 +vt 0.317063 0.139995 +vt 0.327692 0.115886 +vt 0.291900 0.159996 +vt 0.299242 0.133555 +vt 0.307269 0.107991 +vt 0.315959 0.082871 +vt 0.325296 0.057677 +vt 0.335284 0.031720 +vt 0.279342 0.217017 +vt 0.285266 0.187700 +vt 0.299855 0.049111 +vt 0.308360 0.022381 +vt 0.273275 0.216467 +vt 0.274090 0.186190 +vt 0.276456 0.157179 +vt 0.280338 0.129215 +vt 0.285630 0.102075 +vt 0.292196 0.075493 +vt 0.260296 0.156605 +vt 0.260296 0.127156 +vt 0.262576 0.098207 +vt 0.266993 0.069785 +vt 0.273284 0.041887 +vt 0.280981 0.014424 +vt 0.267186 0.217028 +vt 0.262617 0.186536 +vt 0.478275 0.575178 +vt 0.466108 0.603512 +vt 0.461011 0.600503 +vt 0.357244 0.741258 +vt 0.334067 0.759173 +vt 0.316446 0.735681 +vt 0.339906 0.719060 +vt 0.379353 0.722215 +vt 0.362280 0.702258 +vt 0.400085 0.701700 +vt 0.383716 0.684686 +vt 0.419231 0.679571 +vt 0.404285 0.665961 +vt 0.436650 0.655795 +vt 0.424019 0.645809 +vt 0.452269 0.630411 +vt 0.442927 0.624028 +vt 0.369847 0.666822 +vt 0.391713 0.651154 +vt 0.413358 0.634418 +vt 0.434946 0.616316 +vt 0.456578 0.596621 +vt 0.300261 0.711288 +vt 0.324490 0.696407 +vt 0.347540 0.681767 +vt 0.452938 0.592006 +vt 0.285945 0.685844 +vt 0.311102 0.672966 +vt 0.335012 0.660520 +vt 0.358281 0.648079 +vt 0.381368 0.635294 +vt 0.404647 0.621863 +vt 0.428428 0.607510 +vt 0.373184 0.618476 +vt 0.397893 0.608329 +vt 0.423460 0.597822 +vt 0.450200 0.586811 +vt 0.273749 0.659366 +vt 0.299836 0.648633 +vt 0.324662 0.638417 +vt 0.348930 0.628440 +vt 0.290734 0.623405 +vt 0.316479 0.615416 +vt 0.341772 0.607897 +vt 0.367159 0.600767 +vt 0.393137 0.593964 +vt 0.420125 0.587451 +vt 0.448449 0.581199 +vt 0.263791 0.631962 +vt 0.390461 0.578901 +vt 0.418512 0.576591 +vt 0.447747 0.575345 +vt 0.256065 0.603793 +vt 0.283767 0.597314 +vt 0.310443 0.591495 +vt 0.336815 0.586433 +vt 0.363341 0.582209 +vt 0.278797 0.570347 +vt 0.306518 0.566554 +vt 0.334106 0.563971 +vt 0.361847 0.562818 +vt 0.389996 0.563270 +vt 0.418721 0.565454 +vt 0.448135 0.569434 +vt 0.250405 0.575044 +vt 0.391939 0.547227 +vt 0.420859 0.554281 +vt 0.449626 0.563665 +vt 0.246401 0.545909 +vt 0.275509 0.542335 +vt 0.304623 0.540317 +vt 0.333769 0.540318 +vt 0.362891 0.542580 +vt 0.761811 0.347681 +vt 0.768908 0.318727 +vt 0.780094 0.320881 +vt 0.777874 0.349643 +vt 0.757134 0.376765 +vt 0.777395 0.377824 +vt 0.754853 0.405922 +vt 0.778527 0.405595 +vt 0.754853 0.435093 +vt 0.781108 0.433185 +vt 0.756891 0.464239 +vt 0.784920 0.460921 +vt 0.760508 0.493374 +vt 0.789651 0.489316 +vt 0.778345 0.289928 +vt 0.789919 0.261250 +vt 0.784121 0.291430 +vt 0.806069 0.429255 +vt 0.811888 0.455932 +vt 0.818384 0.483616 +vt 0.790041 0.291827 +vt 0.791247 0.321105 +vt 0.793525 0.349194 +vt 0.796808 0.376345 +vt 0.801016 0.402895 +vt 0.808608 0.346533 +vt 0.815385 0.372542 +vt 0.822496 0.397949 +vt 0.829996 0.423234 +vt 0.837962 0.448965 +vt 0.846513 0.475871 +vt 0.795905 0.291132 +vt 0.802124 0.319505 +vt 0.863157 0.439887 +vt 0.873856 0.465923 +vt 0.801527 0.289386 +vt 0.812514 0.316180 +vt 0.822994 0.341792 +vt 0.833114 0.366534 +vt 0.843047 0.390809 +vt 0.852991 0.415079 +vt 0.849954 0.358372 +vt 0.862699 0.381487 +vt 0.875090 0.404766 +vt 0.887452 0.428664 +vt 0.900261 0.453770 +vt 0.806735 0.286652 +vt 0.822222 0.311220 +vt 0.836553 0.335052 +vt 0.811362 0.283014 +vt 0.831050 0.304708 +vt 0.849136 0.326354 +vt 0.865844 0.348051 +vt 0.881467 0.369960 +vt 0.896347 0.392297 +vt 0.910870 0.415352 +vt 0.925629 0.439546 +vt 0.880692 0.335502 +vt 0.899375 0.356137 +vt 0.916877 0.377637 +vt 0.933539 0.400050 +vt 0.949961 0.423523 +vt 0.815258 0.278580 +vt 0.838787 0.296729 +vt 0.860562 0.315703 +vt 0.818280 0.273480 +vt 0.845196 0.287385 +vt 0.870586 0.303076 +vt 0.894356 0.320575 +vt 0.916459 0.339810 +vt 0.936922 0.360645 +vt 0.955850 0.382862 +vt 0.973431 0.406172 +vt 0.599044 0.014424 +vt 0.628498 0.014424 +vt 0.626437 0.034472 +vt 0.598469 0.030587 +vt 0.569110 0.016746 +vt 0.569456 0.028219 +vt 0.538618 0.021316 +vt 0.539178 0.027405 +vt 0.507124 0.028202 +vt 0.713744 0.027395 +vt 0.741217 0.035092 +vt 0.733260 0.062481 +vt 0.706520 0.053978 +vt 0.685832 0.021104 +vt 0.680127 0.046323 +vt 0.657458 0.016705 +vt 0.653584 0.039773 +vt 0.697957 0.079428 +vt 0.672754 0.070095 +vt 0.647660 0.061415 +vt 0.622094 0.053379 +vt 0.595651 0.046032 +vt 0.567945 0.039396 +vt 0.538628 0.033472 +vt 0.723921 0.089414 +vt 0.590779 0.060649 +vt 0.564698 0.050066 +vt 0.537002 0.039331 +vt 0.712797 0.115663 +vt 0.687699 0.103882 +vt 0.663578 0.092677 +vt 0.639757 0.081836 +vt 0.615649 0.071200 +vt 0.675575 0.127351 +vt 0.652510 0.114176 +vt 0.629889 0.101138 +vt 0.607197 0.087948 +vt 0.583980 0.074337 +vt 0.559822 0.060043 +vt 0.534354 0.044807 +vt 0.699719 0.141045 +vt 0.575328 0.086988 +vt 0.553411 0.069149 +vt 0.530762 0.049736 +vt 0.684668 0.165423 +vt 0.661528 0.149822 +vt 0.639496 0.134643 +vt 0.618037 0.119363 +vt 0.596769 0.103605 +vt 0.624491 0.154131 +vt 0.604145 0.136532 +vt 0.584342 0.118117 +vt 0.564860 0.098465 +vt 0.545554 0.077199 +vt 0.526322 0.053960 +vt 0.667740 0.188724 +vt 0.645566 0.171320 +vt 0.536344 0.083989 +vt 0.521155 0.057333 +vt 0.649146 0.210979 +vt 0.627736 0.191978 +vt 0.607418 0.172754 +vt 0.588093 0.152664 +vt 0.569830 0.131393 +vt 0.552575 0.108592 +vt 0.569644 0.167783 +vt 0.553064 0.143280 +vt 0.538450 0.117119 +vt 0.525891 0.089282 +vt 0.515406 0.059719 +vt 0.629261 0.232402 +vt 0.608070 0.212158 +vt 0.588093 0.190735 +vn 0.0000 -0.5528 -0.8333 +vn 0.0000 -0.3805 -0.9247 +vn 0.1804 -0.3805 -0.9070 +vn 0.1626 -0.5528 -0.8173 +vn 0.0000 -0.7040 -0.7101 +vn 0.1385 -0.7040 -0.6965 +vn 0.0000 -0.8286 -0.5598 +vn 0.1092 -0.8286 -0.5490 +vn 0.0000 -0.9217 -0.3879 +vn 0.0757 -0.9217 -0.3804 +vn 0.0000 -0.9796 -0.2010 +vn 0.0392 -0.9796 -0.1971 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 -0.1939 -0.9810 +vn 0.0000 0.0000 -1.0000 +vn 0.1951 0.0000 -0.9808 +vn 0.1914 -0.1939 -0.9622 +vn 0.3754 -0.1939 -0.9063 +vn 0.3539 -0.3805 -0.8544 +vn 0.3189 -0.5528 -0.7699 +vn 0.2717 -0.7040 -0.6561 +vn 0.2142 -0.8286 -0.5171 +vn 0.1484 -0.9217 -0.3583 +vn 0.0769 -0.9796 -0.1856 +vn 0.3827 0.0000 -0.9239 +vn 0.3110 -0.8286 -0.4654 +vn 0.2155 -0.9217 -0.3225 +vn 0.1116 -0.9796 -0.1671 +vn 0.5556 0.0000 -0.8314 +vn 0.5450 -0.1939 -0.8157 +vn 0.5137 -0.3805 -0.7689 +vn 0.4630 -0.5528 -0.6929 +vn 0.3945 -0.7040 -0.5904 +vn 0.6539 -0.3805 -0.6539 +vn 0.5893 -0.5528 -0.5893 +vn 0.5021 -0.7040 -0.5021 +vn 0.3958 -0.8286 -0.3958 +vn 0.2743 -0.9217 -0.2743 +vn 0.1421 -0.9796 -0.1421 +vn 0.7071 0.0000 -0.7071 +vn 0.6937 -0.1939 -0.6937 +vn 0.3225 -0.9217 -0.2155 +vn 0.1671 -0.9796 -0.1116 +vn 0.8314 0.0000 -0.5556 +vn 0.8157 -0.1939 -0.5450 +vn 0.7689 -0.3805 -0.5137 +vn 0.6929 -0.5528 -0.4630 +vn 0.5904 -0.7040 -0.3945 +vn 0.4654 -0.8286 -0.3110 +vn 0.8544 -0.3805 -0.3539 +vn 0.7699 -0.5528 -0.3189 +vn 0.6561 -0.7040 -0.2717 +vn 0.5171 -0.8286 -0.2142 +vn 0.3583 -0.9217 -0.1484 +vn 0.1856 -0.9796 -0.0769 +vn 0.9239 0.0000 -0.3827 +vn 0.9063 -0.1939 -0.3754 +vn 0.3804 -0.9217 -0.0757 +vn 0.1971 -0.9796 -0.0392 +vn 0.9808 0.0000 -0.1951 +vn 0.9622 -0.1939 -0.1914 +vn 0.9070 -0.3805 -0.1804 +vn 0.8173 -0.5528 -0.1626 +vn 0.6965 -0.7040 -0.1385 +vn 0.5490 -0.8286 -0.1092 +vn 0.8333 -0.5528 0.0000 +vn 0.7101 -0.7040 0.0000 +vn 0.5598 -0.8286 0.0000 +vn 0.3879 -0.9217 0.0000 +vn 0.2010 -0.9796 0.0000 +vn 1.0000 0.0000 0.0000 +vn 0.9810 -0.1939 0.0000 +vn 0.9247 -0.3805 0.0000 +vn 0.9810 0.1939 0.0000 +vn 0.9622 0.1939 0.1914 +vn 0.9808 0.0000 0.1951 +vn 0.2010 0.9796 0.0000 +vn 0.0000 1.0000 0.0000 +vn 0.1971 0.9796 0.0392 +vn 0.3879 0.9217 0.0000 +vn 0.3804 0.9217 0.0757 +vn 0.5598 0.8286 0.0000 +vn 0.5490 0.8286 0.1092 +vn 0.7101 0.7040 0.0000 +vn 0.6965 0.7040 0.1385 +vn 0.8333 0.5528 0.0000 +vn 0.8173 0.5528 0.1626 +vn 0.9247 0.3805 0.0000 +vn 0.9070 0.3805 0.1804 +vn 0.6561 0.7040 0.2717 +vn 0.7699 0.5528 0.3189 +vn 0.8544 0.3805 0.3539 +vn 0.9063 0.1939 0.3754 +vn 0.9239 0.0000 0.3827 +vn 0.1856 0.9796 0.0769 +vn 0.3583 0.9217 0.1484 +vn 0.5171 0.8286 0.2142 +vn 0.1671 0.9796 0.1116 +vn 0.3225 0.9217 0.2155 +vn 0.4654 0.8286 0.3110 +vn 0.5904 0.7040 0.3945 +vn 0.6929 0.5528 0.4630 +vn 0.7689 0.3805 0.5137 +vn 0.8157 0.1939 0.5450 +vn 0.8314 0.0000 0.5556 +vn 0.5893 0.5528 0.5893 +vn 0.6539 0.3805 0.6539 +vn 0.6937 0.1939 0.6937 +vn 0.7071 0.0000 0.7071 +vn 0.1421 0.9796 0.1421 +vn 0.2743 0.9217 0.2743 +vn 0.3958 0.8286 0.3958 +vn 0.5021 0.7040 0.5021 +vn 0.1116 0.9796 0.1671 +vn 0.2155 0.9217 0.3225 +vn 0.3110 0.8286 0.4654 +vn 0.3945 0.7040 0.5904 +vn 0.4630 0.5528 0.6929 +vn 0.5137 0.3805 0.7689 +vn 0.5450 0.1939 0.8157 +vn 0.5556 0.0000 0.8314 +vn 0.3189 0.5528 0.7699 +vn 0.3539 0.3805 0.8544 +vn 0.3754 0.1939 0.9063 +vn 0.3827 0.0000 0.9239 +vn 0.0769 0.9796 0.1856 +vn 0.1484 0.9217 0.3583 +vn 0.2142 0.8286 0.5171 +vn 0.2717 0.7040 0.6561 +vn 0.0757 0.9217 0.3804 +vn 0.1092 0.8286 0.5490 +vn 0.1385 0.7040 0.6965 +vn 0.1626 0.5528 0.8173 +vn 0.1804 0.3805 0.9070 +vn 0.1914 0.1939 0.9622 +vn 0.1951 0.0000 0.9808 +vn 0.0392 0.9796 0.1971 +vn 0.0000 0.3805 0.9247 +vn 0.0000 0.1939 0.9810 +vn 0.0000 0.0000 1.0000 +vn 0.0000 0.9796 0.2010 +vn 0.0000 0.9217 0.3879 +vn 0.0000 0.8286 0.5598 +vn 0.0000 0.7040 0.7101 +vn 0.0000 0.5528 0.8333 +vn 0.0000 -0.5528 0.8333 +vn 0.0000 -0.3805 0.9247 +vn -0.1804 -0.3805 0.9070 +vn -0.1626 -0.5528 0.8173 +vn 0.0000 -0.7040 0.7101 +vn -0.1385 -0.7040 0.6965 +vn 0.0000 -0.8286 0.5598 +vn -0.1092 -0.8286 0.5490 +vn 0.0000 -0.9217 0.3879 +vn -0.0757 -0.9217 0.3804 +vn 0.0000 -0.9796 0.2010 +vn -0.0392 -0.9796 0.1971 +vn 0.0000 -0.1939 0.9810 +vn -0.1951 0.0000 0.9808 +vn -0.1914 -0.1939 0.9622 +vn -0.1484 -0.9217 0.3583 +vn -0.0769 -0.9796 0.1856 +vn -0.3827 0.0000 0.9239 +vn -0.3754 -0.1939 0.9063 +vn -0.3539 -0.3805 0.8544 +vn -0.3189 -0.5528 0.7699 +vn -0.2717 -0.7040 0.6561 +vn -0.2142 -0.8286 0.5171 +vn -0.5137 -0.3805 0.7689 +vn -0.4630 -0.5528 0.6929 +vn -0.3945 -0.7040 0.5904 +vn -0.3110 -0.8286 0.4654 +vn -0.2155 -0.9217 0.3225 +vn -0.1116 -0.9796 0.1671 +vn -0.5556 0.0000 0.8314 +vn -0.5450 -0.1939 0.8157 +vn -0.2743 -0.9217 0.2743 +vn -0.1421 -0.9796 0.1421 +vn -0.7071 0.0000 0.7071 +vn -0.6937 -0.1939 0.6937 +vn -0.6539 -0.3805 0.6539 +vn -0.5893 -0.5528 0.5893 +vn -0.5021 -0.7040 0.5021 +vn -0.3958 -0.8286 0.3958 +vn -0.6929 -0.5528 0.4630 +vn -0.5904 -0.7040 0.3945 +vn -0.4654 -0.8286 0.3110 +vn -0.3225 -0.9217 0.2155 +vn -0.1671 -0.9796 0.1116 +vn -0.8314 0.0000 0.5556 +vn -0.8157 -0.1939 0.5450 +vn -0.7689 -0.3805 0.5137 +vn -0.1856 -0.9796 0.0769 +vn -0.9239 0.0000 0.3827 +vn -0.9063 -0.1939 0.3754 +vn -0.8544 -0.3805 0.3539 +vn -0.7699 -0.5528 0.3189 +vn -0.6561 -0.7040 0.2717 +vn -0.5171 -0.8286 0.2142 +vn -0.3583 -0.9217 0.1484 +vn -0.6965 -0.7040 0.1385 +vn -0.5490 -0.8286 0.1092 +vn -0.3804 -0.9217 0.0757 +vn -0.1971 -0.9796 0.0392 +vn -0.9808 0.0000 0.1951 +vn -0.9622 -0.1939 0.1914 +vn -0.9070 -0.3805 0.1804 +vn -0.8173 -0.5528 0.1626 +vn -1.0000 0.0000 0.0000 +vn -0.9810 -0.1939 0.0000 +vn -0.9247 -0.3805 0.0000 +vn -0.8333 -0.5528 0.0000 +vn -0.7101 -0.7040 0.0000 +vn -0.5598 -0.8286 0.0000 +vn -0.3879 -0.9217 0.0000 +vn -0.2010 -0.9796 0.0000 +vn -0.9247 0.3805 0.0000 +vn -0.8333 0.5528 0.0000 +vn -0.8173 0.5528 -0.1626 +vn -0.9070 0.3805 -0.1804 +vn -0.9810 0.1939 0.0000 +vn -0.9622 0.1939 -0.1914 +vn -0.9808 0.0000 -0.1951 +vn -0.2010 0.9796 0.0000 +vn -0.1971 0.9796 -0.0392 +vn -0.3879 0.9217 0.0000 +vn -0.3804 0.9217 -0.0757 +vn -0.5598 0.8286 0.0000 +vn -0.5490 0.8286 -0.1092 +vn -0.7101 0.7040 0.0000 +vn -0.6965 0.7040 -0.1385 +vn -0.1856 0.9796 -0.0769 +vn -0.3583 0.9217 -0.1484 +vn -0.5171 0.8286 -0.2142 +vn -0.6561 0.7040 -0.2717 +vn -0.7699 0.5528 -0.3189 +vn -0.8544 0.3805 -0.3539 +vn -0.9063 0.1939 -0.3754 +vn -0.9239 0.0000 -0.3827 +vn -0.6929 0.5528 -0.4630 +vn -0.7689 0.3805 -0.5137 +vn -0.8157 0.1939 -0.5450 +vn -0.8314 0.0000 -0.5556 +vn -0.1671 0.9796 -0.1116 +vn -0.3225 0.9217 -0.2155 +vn -0.4654 0.8286 -0.3110 +vn -0.5904 0.7040 -0.3945 +vn -0.2743 0.9217 -0.2743 +vn -0.3958 0.8286 -0.3958 +vn -0.5021 0.7040 -0.5021 +vn -0.5893 0.5528 -0.5893 +vn -0.6539 0.3805 -0.6539 +vn -0.6937 0.1939 -0.6937 +vn -0.7071 0.0000 -0.7071 +vn -0.1421 0.9796 -0.1421 +vn -0.5137 0.3805 -0.7689 +vn -0.5450 0.1939 -0.8157 +vn -0.5556 0.0000 -0.8314 +vn -0.1116 0.9796 -0.1671 +vn -0.2155 0.9217 -0.3225 +vn -0.3110 0.8286 -0.4654 +vn -0.3945 0.7040 -0.5904 +vn -0.4630 0.5528 -0.6929 +vn -0.2142 0.8286 -0.5171 +vn -0.2717 0.7040 -0.6561 +vn -0.3189 0.5528 -0.7699 +vn -0.3539 0.3805 -0.8544 +vn -0.3754 0.1939 -0.9063 +vn -0.3827 0.0000 -0.9239 +vn -0.0769 0.9796 -0.1856 +vn -0.1484 0.9217 -0.3583 +vn -0.1914 0.1939 -0.9622 +vn -0.1951 0.0000 -0.9808 +vn -0.0392 0.9796 -0.1971 +vn -0.0757 0.9217 -0.3804 +vn -0.1092 0.8286 -0.5490 +vn -0.1385 0.7040 -0.6965 +vn -0.1626 0.5528 -0.8173 +vn -0.1804 0.3805 -0.9070 +vn 0.0000 0.8286 -0.5598 +vn 0.0000 0.7040 -0.7101 +vn 0.0000 0.5528 -0.8333 +vn 0.0000 0.3805 -0.9247 +vn 0.0000 0.1939 -0.9810 +vn 0.0000 0.9796 -0.2010 +vn 0.0000 0.9217 -0.3879 +vn -0.7348 0.0000 -0.6783 +vn 0.7348 0.0000 -0.6783 +vn 0.0000 0.2706 0.9627 +vn -0.5165 0.7204 -0.4628 +vn 0.5165 0.7204 -0.4628 +vn 0.0000 0.2539 0.9672 +vn -0.7335 0.6796 0.0000 +vn 0.7335 0.6796 0.0000 +vn 0.1092 0.8286 -0.5490 +vn 0.1385 0.7040 -0.6965 +vn 0.1626 0.5528 -0.8173 +vn 0.1804 0.3805 -0.9070 +vn 0.1914 0.1939 -0.9622 +vn 0.0392 0.9796 -0.1971 +vn 0.0757 0.9217 -0.3804 +vn 0.1484 0.9217 -0.3583 +vn 0.2142 0.8286 -0.5171 +vn 0.2717 0.7040 -0.6561 +vn 0.3189 0.5528 -0.7699 +vn 0.3539 0.3805 -0.8544 +vn 0.3754 0.1939 -0.9063 +vn 0.0769 0.9796 -0.1856 +vn 0.5137 0.3805 -0.7689 +vn 0.5450 0.1939 -0.8157 +vn 0.1116 0.9796 -0.1671 +vn 0.2155 0.9217 -0.3225 +vn 0.3110 0.8286 -0.4654 +vn 0.3945 0.7040 -0.5904 +vn 0.4630 0.5528 -0.6929 +vn 0.2743 0.9217 -0.2743 +vn 0.3958 0.8286 -0.3958 +vn 0.5021 0.7040 -0.5021 +vn 0.5893 0.5528 -0.5893 +vn 0.6539 0.3805 -0.6539 +vn 0.6937 0.1939 -0.6937 +vn 0.1421 0.9796 -0.1421 +vn 0.7689 0.3805 -0.5137 +vn 0.8157 0.1939 -0.5450 +vn 0.1671 0.9796 -0.1116 +vn 0.3225 0.9217 -0.2155 +vn 0.4654 0.8286 -0.3110 +vn 0.5904 0.7040 -0.3945 +vn 0.6929 0.5528 -0.4630 +vn 0.5171 0.8286 -0.2142 +vn 0.6561 0.7040 -0.2717 +vn 0.7699 0.5528 -0.3189 +vn 0.8544 0.3805 -0.3539 +vn 0.9063 0.1939 -0.3754 +vn 0.1856 0.9796 -0.0769 +vn 0.3583 0.9217 -0.1484 +vn 0.9622 0.1939 -0.1914 +vn 0.1971 0.9796 -0.0392 +vn 0.3804 0.9217 -0.0757 +vn 0.5490 0.8286 -0.1092 +vn 0.6965 0.7040 -0.1385 +vn 0.8173 0.5528 -0.1626 +vn 0.9070 0.3805 -0.1804 +vn 0.1971 -0.9796 0.0392 +vn 0.9622 -0.1939 0.1914 +vn 0.9070 -0.3805 0.1804 +vn 0.8173 -0.5528 0.1626 +vn 0.6965 -0.7040 0.1385 +vn 0.5490 -0.8286 0.1092 +vn 0.3804 -0.9217 0.0757 +vn 0.7699 -0.5528 0.3189 +vn 0.6561 -0.7040 0.2717 +vn 0.5171 -0.8286 0.2142 +vn 0.3583 -0.9217 0.1484 +vn 0.1856 -0.9796 0.0769 +vn 0.9063 -0.1939 0.3754 +vn 0.8544 -0.3805 0.3539 +vn 0.1671 -0.9796 0.1116 +vn 0.8157 -0.1939 0.5450 +vn 0.7689 -0.3805 0.5137 +vn 0.6929 -0.5528 0.4630 +vn 0.5904 -0.7040 0.3945 +vn 0.4654 -0.8286 0.3110 +vn 0.3225 -0.9217 0.2155 +vn 0.5021 -0.7040 0.5021 +vn 0.3958 -0.8286 0.3958 +vn 0.2743 -0.9217 0.2743 +vn 0.1421 -0.9796 0.1421 +vn 0.6937 -0.1939 0.6937 +vn 0.6539 -0.3805 0.6539 +vn 0.5893 -0.5528 0.5893 +vn 0.5450 -0.1939 0.8157 +vn 0.5137 -0.3805 0.7689 +vn 0.4630 -0.5528 0.6929 +vn 0.3945 -0.7040 0.5904 +vn 0.3110 -0.8286 0.4654 +vn 0.2155 -0.9217 0.3225 +vn 0.1116 -0.9796 0.1671 +vn 0.2142 -0.8286 0.5171 +vn 0.1484 -0.9217 0.3583 +vn 0.0769 -0.9796 0.1856 +vn 0.3754 -0.1939 0.9063 +vn 0.3539 -0.3805 0.8544 +vn 0.3189 -0.5528 0.7699 +vn 0.2717 -0.7040 0.6561 +vn 0.1914 -0.1939 0.9622 +vn 0.1804 -0.3805 0.9070 +vn 0.1626 -0.5528 0.8173 +vn 0.1385 -0.7040 0.6965 +vn 0.1092 -0.8286 0.5490 +vn 0.0757 -0.9217 0.3804 +vn 0.0392 -0.9796 0.1971 +vn -0.0757 0.9217 0.3804 +vn -0.1092 0.8286 0.5490 +vn -0.1385 0.7040 0.6965 +vn -0.1626 0.5528 0.8173 +vn -0.1804 0.3805 0.9070 +vn -0.1914 0.1939 0.9622 +vn -0.0392 0.9796 0.1971 +vn -0.3539 0.3805 0.8544 +vn -0.3754 0.1939 0.9063 +vn -0.0769 0.9796 0.1856 +vn -0.1484 0.9217 0.3583 +vn -0.2142 0.8286 0.5171 +vn -0.2717 0.7040 0.6561 +vn -0.3189 0.5528 0.7699 +vn -0.3110 0.8286 0.4654 +vn -0.3945 0.7040 0.5904 +vn -0.4630 0.5528 0.6929 +vn -0.5137 0.3805 0.7689 +vn -0.5450 0.1939 0.8157 +vn -0.1116 0.9796 0.1671 +vn -0.2155 0.9217 0.3225 +vn -0.6937 0.1939 0.6937 +vn -0.1421 0.9796 0.1421 +vn -0.2743 0.9217 0.2743 +vn -0.3958 0.8286 0.3958 +vn -0.5021 0.7040 0.5021 +vn -0.5893 0.5528 0.5893 +vn -0.6539 0.3805 0.6539 +vn -0.5904 0.7040 0.3945 +vn -0.6929 0.5528 0.4630 +vn -0.7689 0.3805 0.5137 +vn -0.8157 0.1939 0.5450 +vn -0.1671 0.9796 0.1116 +vn -0.3225 0.9217 0.2155 +vn -0.4654 0.8286 0.3110 +vn -0.1856 0.9796 0.0769 +vn -0.3583 0.9217 0.1484 +vn -0.5171 0.8286 0.2142 +vn -0.6561 0.7040 0.2717 +vn -0.7699 0.5528 0.3189 +vn -0.8544 0.3805 0.3539 +vn -0.9063 0.1939 0.3754 +vn -0.6965 0.7040 0.1385 +vn -0.8173 0.5528 0.1626 +vn -0.9070 0.3805 0.1804 +vn -0.9622 0.1939 0.1914 +vn -0.1971 0.9796 0.0392 +vn -0.3804 0.9217 0.0757 +vn -0.5490 0.8286 0.1092 +vn -0.6965 -0.7040 -0.1385 +vn -0.5490 -0.8286 -0.1092 +vn -0.3804 -0.9217 -0.0757 +vn -0.1971 -0.9796 -0.0392 +vn -0.9622 -0.1939 -0.1914 +vn -0.9070 -0.3805 -0.1804 +vn -0.8173 -0.5528 -0.1626 +vn -0.9063 -0.1939 -0.3754 +vn -0.8544 -0.3805 -0.3539 +vn -0.7699 -0.5528 -0.3189 +vn -0.6561 -0.7040 -0.2717 +vn -0.5171 -0.8286 -0.2142 +vn -0.3583 -0.9217 -0.1484 +vn -0.1856 -0.9796 -0.0769 +vn -0.4654 -0.8286 -0.3110 +vn -0.3225 -0.9217 -0.2155 +vn -0.1671 -0.9796 -0.1116 +vn -0.8157 -0.1939 -0.5450 +vn -0.7689 -0.3805 -0.5137 +vn -0.6929 -0.5528 -0.4630 +vn -0.5904 -0.7040 -0.3945 +vn -0.6937 -0.1939 -0.6937 +vn -0.6539 -0.3805 -0.6539 +vn -0.5893 -0.5528 -0.5893 +vn -0.5021 -0.7040 -0.5021 +vn -0.3958 -0.8286 -0.3958 +vn -0.2743 -0.9217 -0.2743 +vn -0.1421 -0.9796 -0.1421 +vn -0.3110 -0.8286 -0.4654 +vn -0.2155 -0.9217 -0.3225 +vn -0.1116 -0.9796 -0.1671 +vn -0.5450 -0.1939 -0.8157 +vn -0.5137 -0.3805 -0.7689 +vn -0.4630 -0.5528 -0.6929 +vn -0.3945 -0.7040 -0.5904 +vn -0.3539 -0.3805 -0.8544 +vn -0.3189 -0.5528 -0.7699 +vn -0.2717 -0.7040 -0.6561 +vn -0.2142 -0.8286 -0.5171 +vn -0.1484 -0.9217 -0.3583 +vn -0.0769 -0.9796 -0.1856 +vn -0.3754 -0.1939 -0.9063 +vn -0.0757 -0.9217 -0.3804 +vn -0.0392 -0.9796 -0.1971 +vn -0.1914 -0.1939 -0.9622 +vn -0.1804 -0.3805 -0.9070 +vn -0.1626 -0.5528 -0.8173 +vn -0.1385 -0.7040 -0.6965 +vn -0.1092 -0.8286 -0.5490 +s 1 +f 479/1/1 478/2/2 20/3/3 21/4/4 +f 480/5/5 479/1/1 21/4/4 22/6/6 +f 10/7/7 480/5/5 22/6/6 23/8/8 +f 481/9/9 10/7/7 23/8/8 24/10/10 +f 482/11/11 481/9/9 24/10/10 25/12/12 +f 206/13/13 482/11/11 25/12/12 +f 9/14/14 8/15/15 18/16/16 19/17/17 +f 478/2/2 9/14/14 19/17/17 20/3/3 +f 20/3/3 19/17/17 34/18/18 35/19/19 +f 21/4/4 20/3/3 35/19/19 36/20/20 +f 22/6/6 21/4/4 36/20/20 37/21/21 +f 23/8/8 22/6/6 37/21/21 38/22/22 +f 24/10/10 23/8/8 38/22/22 39/23/23 +f 25/12/12 24/10/10 39/23/23 40/24/24 +f 206/13/13 25/12/12 40/24/24 +f 19/17/17 18/16/16 33/25/25 34/18/18 +f 39/23/23 38/22/22 53/26/26 54/27/27 +f 40/24/24 39/23/23 54/27/27 55/28/28 +f 206/13/13 40/24/24 55/28/28 +f 34/18/18 33/25/25 48/29/29 49/30/30 +f 35/19/19 34/18/18 49/30/30 50/31/31 +f 36/20/20 35/19/19 50/31/31 51/32/32 +f 37/21/21 36/20/20 51/32/32 52/33/33 +f 38/22/22 37/21/21 52/33/33 53/26/26 +f 51/32/32 50/31/31 65/34/34 66/35/35 +f 52/33/33 51/32/32 66/35/35 67/36/36 +f 53/26/26 52/33/33 67/36/36 68/37/37 +f 54/27/27 53/26/26 68/37/37 69/38/38 +f 55/28/28 54/27/27 69/38/38 70/39/39 +f 206/13/13 55/28/28 70/39/39 +f 49/30/30 48/29/29 63/40/40 64/41/41 +f 50/31/31 49/30/30 64/41/41 65/34/34 +f 70/39/39 69/38/38 84/42/42 85/43/43 +f 206/13/13 70/39/39 85/43/43 +f 64/41/41 63/40/40 78/44/44 79/45/45 +f 65/34/34 64/41/41 79/45/45 80/46/46 +f 66/35/35 65/34/34 80/46/46 81/47/47 +f 67/36/36 66/35/35 81/47/47 82/48/48 +f 68/37/37 67/36/36 82/48/48 83/49/49 +f 69/38/38 68/37/37 83/49/49 84/42/42 +f 81/47/47 80/46/46 95/50/50 96/51/51 +f 82/48/48 81/47/47 96/51/51 97/52/52 +f 83/49/49 82/48/48 97/52/52 98/53/53 +f 84/42/42 83/49/49 98/53/53 99/54/54 +f 85/43/43 84/42/42 99/54/54 100/55/55 +f 206/13/13 85/43/43 100/55/55 +f 79/45/45 78/44/44 93/56/56 94/57/57 +f 80/46/46 79/45/45 94/57/57 95/50/50 +f 100/55/55 99/54/54 114/58/58 115/59/59 +f 206/13/13 100/55/55 115/59/59 +f 94/57/57 93/56/56 108/60/60 109/61/61 +f 95/50/50 94/57/57 109/61/61 110/62/62 +f 96/51/51 95/50/50 110/62/62 111/63/63 +f 97/52/52 96/51/51 111/63/63 112/64/64 +f 98/53/53 97/52/52 112/64/64 113/65/65 +f 99/54/54 98/53/53 113/65/65 114/58/58 +f 112/64/64 111/63/63 126/66/66 127/67/67 +f 113/65/65 112/64/64 127/67/67 128/68/68 +f 114/58/58 113/65/65 128/68/68 129/69/69 +f 115/59/59 114/58/58 129/69/69 130/70/70 +f 206/13/13 115/59/59 130/70/70 +f 109/61/61 108/60/60 123/71/71 124/72/72 +f 110/62/62 109/61/61 124/72/72 125/73/73 +f 111/63/63 110/62/62 125/73/73 126/66/66 +f 123/74/71 122/75/74 137/76/75 138/77/76 +f 116/78/77 297/79/78 131/80/79 +f 117/81/80 116/78/77 131/80/79 132/82/81 +f 118/83/82 117/81/80 132/82/81 133/84/83 +f 119/85/84 118/83/82 133/84/83 134/86/85 +f 120/87/86 119/85/84 134/86/85 135/88/87 +f 121/89/88 120/87/86 135/88/87 136/90/89 +f 122/75/74 121/89/88 136/90/89 137/76/75 +f 135/88/87 134/86/85 149/91/90 150/92/91 +f 136/90/89 135/88/87 150/92/91 151/93/92 +f 137/76/75 136/90/89 151/93/92 152/94/93 +f 138/77/76 137/76/75 152/94/93 153/95/94 +f 131/80/79 297/79/78 146/96/95 +f 132/82/81 131/80/79 146/96/95 147/97/96 +f 133/84/83 132/82/81 147/97/96 148/98/97 +f 134/86/85 133/84/83 148/98/97 149/91/90 +f 147/97/96 146/96/95 161/99/98 162/100/99 +f 148/98/97 147/97/96 162/100/99 163/101/100 +f 149/91/90 148/98/97 163/101/100 164/102/101 +f 150/92/91 149/91/90 164/102/101 165/103/102 +f 151/93/92 150/92/91 165/103/102 166/104/103 +f 152/94/93 151/93/92 166/104/103 167/105/104 +f 153/95/94 152/94/93 167/105/104 168/106/105 +f 146/96/95 297/79/78 161/99/98 +f 166/104/103 165/103/102 180/107/106 181/108/107 +f 167/105/104 166/104/103 181/108/107 182/109/108 +f 168/106/105 167/105/104 182/109/108 183/110/109 +f 161/99/98 297/79/78 176/111/110 +f 162/100/99 161/99/98 176/111/110 177/112/111 +f 163/101/100 162/100/99 177/112/111 178/113/112 +f 164/102/101 163/101/100 178/113/112 179/114/113 +f 165/103/102 164/102/101 179/114/113 180/107/106 +f 177/112/111 176/111/110 191/115/114 192/116/115 +f 178/113/112 177/112/111 192/116/115 193/117/116 +f 179/114/113 178/113/112 193/117/116 194/118/117 +f 180/107/106 179/114/113 194/118/117 195/119/118 +f 181/108/107 180/107/106 195/119/118 196/120/119 +f 182/109/108 181/108/107 196/120/119 197/121/120 +f 183/110/109 182/109/108 197/121/120 198/122/121 +f 176/111/110 297/79/78 191/115/114 +f 196/120/119 195/119/118 211/123/122 212/124/123 +f 197/121/120 196/120/119 212/124/123 213/125/124 +f 198/122/121 197/121/120 213/125/124 214/126/125 +f 191/115/114 297/79/78 207/127/126 +f 192/116/115 191/115/114 207/127/126 208/128/127 +f 193/117/116 192/116/115 208/128/127 209/129/128 +f 194/118/117 193/117/116 209/129/128 210/130/129 +f 195/119/118 194/118/117 210/130/129 211/123/122 +f 209/129/128 208/128/127 223/131/130 224/132/131 +f 210/130/129 209/129/128 224/132/131 225/133/132 +f 211/123/122 210/130/129 225/133/132 226/134/133 +f 212/124/123 211/123/122 226/134/133 227/135/134 +f 213/125/124 212/124/123 227/135/134 228/136/135 +f 214/126/125 213/125/124 228/136/135 229/137/136 +f 207/127/126 297/79/78 222/138/137 +f 208/128/127 207/127/126 222/138/137 223/131/130 +f 228/136/135 227/135/134 242/139/138 243/140/139 +f 229/137/136 228/136/135 243/140/139 244/141/140 +f 222/138/137 297/79/78 237/142/141 +f 223/131/130 222/138/137 237/142/141 238/143/142 +f 224/132/131 223/131/130 238/143/142 239/144/143 +f 225/133/132 224/132/131 239/144/143 240/145/144 +f 226/134/133 225/133/132 240/145/144 241/146/145 +f 227/135/134 226/134/133 241/146/145 242/139/138 +f 247/147/146 246/148/147 261/149/148 262/150/149 +f 248/151/150 247/147/146 262/150/149 263/152/151 +f 249/153/152 248/151/150 263/152/151 264/154/153 +f 250/155/154 249/153/152 264/154/153 265/156/155 +f 251/157/156 250/155/154 265/156/155 266/158/157 +f 206/159/13 251/157/156 266/158/157 +f 245/160/158 244/161/140 259/162/159 260/163/160 +f 246/148/147 245/160/158 260/163/160 261/149/148 +f 266/158/157 265/156/155 280/164/161 281/165/162 +f 206/159/13 266/158/157 281/165/162 +f 260/163/160 259/162/159 274/166/163 275/167/164 +f 261/149/148 260/163/160 275/167/164 276/168/165 +f 262/150/149 261/149/148 276/168/165 277/169/166 +f 263/152/151 262/150/149 277/169/166 278/170/167 +f 264/154/153 263/152/151 278/170/167 279/171/168 +f 265/156/155 264/154/153 279/171/168 280/164/161 +f 277/169/166 276/168/165 291/172/169 292/173/170 +f 278/170/167 277/169/166 292/173/170 293/174/171 +f 279/171/168 278/170/167 293/174/171 294/175/172 +f 280/164/161 279/171/168 294/175/172 295/176/173 +f 281/165/162 280/164/161 295/176/173 296/177/174 +f 206/159/13 281/165/162 296/177/174 +f 275/167/164 274/166/163 289/178/175 290/179/176 +f 276/168/165 275/167/164 290/179/176 291/172/169 +f 296/177/174 295/176/173 311/180/177 312/181/178 +f 206/159/13 296/177/174 312/181/178 +f 290/179/176 289/178/175 305/182/179 306/183/180 +f 291/172/169 290/179/176 306/183/180 307/184/181 +f 292/173/170 291/172/169 307/184/181 308/185/182 +f 293/174/171 292/173/170 308/185/182 309/186/183 +f 294/175/172 293/174/171 309/186/183 310/187/184 +f 295/176/173 294/175/172 310/187/184 311/180/177 +f 309/186/183 308/185/182 323/188/185 324/189/186 +f 310/187/184 309/186/183 324/189/186 325/190/187 +f 311/180/177 310/187/184 325/190/187 326/191/188 +f 312/181/178 311/180/177 326/191/188 327/192/189 +f 206/159/13 312/181/178 327/192/189 +f 306/183/180 305/182/179 320/193/190 321/194/191 +f 307/184/181 306/183/180 321/194/191 322/195/192 +f 308/185/182 307/184/181 322/195/192 323/188/185 +f 206/159/13 327/192/189 342/196/193 +f 321/194/191 320/193/190 335/197/194 336/198/195 +f 322/195/192 321/194/191 336/198/195 337/199/196 +f 323/188/185 322/195/192 337/199/196 338/200/197 +f 324/189/186 323/188/185 338/200/197 339/201/198 +f 325/190/187 324/189/186 339/201/198 340/202/199 +f 326/191/188 325/190/187 340/202/199 341/203/200 +f 327/192/189 326/191/188 341/203/200 342/196/193 +f 340/202/199 339/201/198 354/204/201 355/205/202 +f 341/203/200 340/202/199 355/205/202 356/206/203 +f 342/196/193 341/203/200 356/206/203 357/207/204 +f 206/159/13 342/196/193 357/207/204 +f 336/198/195 335/197/194 350/208/205 351/209/206 +f 337/199/196 336/198/195 351/209/206 352/210/207 +f 338/200/197 337/199/196 352/210/207 353/211/208 +f 339/201/198 338/200/197 353/211/208 354/204/201 +f 351/209/206 350/208/205 365/212/209 366/213/210 +f 352/210/207 351/209/206 366/213/210 367/214/211 +f 353/211/208 352/210/207 367/214/211 368/215/212 +f 354/204/201 353/211/208 368/215/212 369/216/213 +f 355/205/202 354/204/201 369/216/213 370/217/214 +f 356/206/203 355/205/202 370/217/214 371/218/215 +f 357/207/204 356/206/203 371/218/215 372/219/216 +f 206/159/13 357/207/204 372/219/216 +f 363/220/217 362/221/218 377/222/219 378/223/220 +f 364/224/221 363/220/217 378/223/220 379/225/222 +f 365/226/209 364/224/221 379/225/222 380/227/223 +f 358/228/224 297/229/78 373/230/225 +f 359/231/226 358/228/224 373/230/225 374/232/227 +f 360/233/228 359/231/226 374/232/227 375/234/229 +f 361/235/230 360/233/228 375/234/229 376/236/231 +f 362/221/218 361/235/230 376/236/231 377/222/219 +f 374/232/227 373/230/225 388/237/232 389/238/233 +f 375/234/229 374/232/227 389/238/233 390/239/234 +f 376/236/231 375/234/229 390/239/234 391/240/235 +f 377/222/219 376/236/231 391/240/235 392/241/236 +f 378/223/220 377/222/219 392/241/236 393/242/237 +f 379/225/222 378/223/220 393/242/237 394/243/238 +f 380/227/223 379/225/222 394/243/238 395/244/239 +f 373/230/225 297/229/78 388/237/232 +f 393/242/237 392/241/236 407/245/240 408/246/241 +f 394/243/238 393/242/237 408/246/241 409/247/242 +f 395/244/239 394/243/238 409/247/242 410/248/243 +f 388/237/232 297/229/78 403/249/244 +f 389/238/233 388/237/232 403/249/244 404/250/245 +f 390/239/234 389/238/233 404/250/245 405/251/246 +f 391/240/235 390/239/234 405/251/246 406/252/247 +f 392/241/236 391/240/235 406/252/247 407/245/240 +f 405/251/246 404/250/245 419/253/248 420/254/249 +f 406/252/247 405/251/246 420/254/249 421/255/250 +f 407/245/240 406/252/247 421/255/250 422/256/251 +f 408/246/241 407/245/240 422/256/251 423/257/252 +f 409/247/242 408/246/241 423/257/252 424/258/253 +f 410/248/243 409/247/242 424/258/253 425/259/254 +f 403/249/244 297/229/78 418/260/255 +f 404/250/245 403/249/244 418/260/255 419/253/248 +f 424/258/253 423/257/252 438/261/256 439/262/257 +f 425/259/254 424/258/253 439/262/257 440/263/258 +f 418/260/255 297/229/78 433/264/259 +f 419/253/248 418/260/255 433/264/259 434/265/260 +f 420/254/249 419/253/248 434/265/260 435/266/261 +f 421/255/250 420/254/249 435/266/261 436/267/262 +f 422/256/251 421/255/250 436/267/262 437/268/263 +f 423/257/252 422/256/251 437/268/263 438/261/256 +f 436/267/262 435/266/261 450/269/264 451/270/265 +f 437/268/263 436/267/262 451/270/265 452/271/266 +f 438/261/256 437/268/263 452/271/266 453/272/267 +f 439/262/257 438/261/256 453/272/267 454/273/268 +f 440/263/258 439/262/257 454/273/268 455/274/269 +f 433/264/259 297/229/78 448/275/270 +f 434/265/260 433/264/259 448/275/270 449/276/271 +f 435/266/261 434/265/260 449/276/271 450/269/264 +f 455/274/269 454/273/268 469/277/272 470/278/273 +f 448/275/270 297/229/78 463/279/274 +f 449/276/271 448/275/270 463/279/274 464/280/275 +f 450/269/264 449/276/271 464/280/275 465/281/276 +f 451/270/265 450/269/264 465/281/276 466/282/277 +f 452/271/266 451/270/265 466/282/277 467/283/278 +f 453/272/267 452/271/266 467/283/278 468/284/279 +f 454/273/268 453/272/267 468/284/279 469/277/272 +f 466/282/277 465/281/276 3/285/280 4/286/281 +f 467/283/278 466/282/277 4/286/281 5/287/282 +f 468/284/279 467/283/278 5/287/282 6/288/283 +f 469/277/272 468/284/279 6/288/283 7/289/284 +f 470/278/273 469/277/272 7/289/284 8/290/15 +f 463/279/274 297/229/78 1/291/285 +f 464/280/275 463/279/274 1/291/285 2/292/286 +f 465/281/276 464/280/275 2/292/286 3/285/280 +s off +f 483/293/13 485/294/13 487/295/13 486/296/13 484/297/13 +f 484/297/13 489/298/13 488/299/13 483/293/13 +f 489/300/71 484/301/71 499/302/71 503/303/71 +f 488/299/140 489/298/140 503/304/140 502/305/140 +f 487/306/287 485/307/287 497/308/287 501/309/287 +f 483/310/209 488/311/209 502/312/209 498/313/209 +f 486/314/288 487/306/288 501/309/288 500/315/288 +f 484/301/140 486/314/140 500/315/140 499/302/140 +f 485/307/140 483/310/140 498/313/140 497/308/140 +f 496/316/78 490/317/78 492/318/78 495/319/78 +f 491/320/78 492/318/78 490/317/78 493/321/78 494/322/78 +f 492/318/289 491/320/289 497/323/289 498/324/289 +f 493/321/289 490/317/289 499/325/289 500/326/289 +f 491/320/290 494/322/290 501/327/290 497/323/290 +f 494/322/291 493/321/291 500/326/291 501/327/291 +f 496/316/292 495/319/292 502/328/292 503/329/292 +f 495/319/293 492/318/293 498/324/293 502/328/293 +f 490/317/294 496/316/294 503/329/294 499/325/294 +s 1 +f 4/330/281 3/331/280 13/332/295 14/333/296 +f 5/334/282 4/330/281 14/333/296 15/335/297 +f 6/336/283 5/334/282 15/335/297 16/337/298 +f 7/338/284 6/336/283 16/337/298 17/339/299 +f 8/340/15 7/338/284 17/339/299 18/341/16 +f 1/342/285 297/343/78 11/344/300 +f 2/345/286 1/342/285 11/344/300 12/346/301 +f 3/331/280 2/345/286 12/346/301 13/332/295 +f 13/332/295 12/346/301 27/347/302 28/348/303 +f 14/333/296 13/332/295 28/348/303 29/349/304 +f 15/335/297 14/333/296 29/349/304 30/350/305 +f 16/337/298 15/335/297 30/350/305 31/351/306 +f 17/339/299 16/337/298 31/351/306 32/352/307 +f 18/341/16 17/339/299 32/352/307 33/353/25 +f 11/344/300 297/343/78 26/354/308 +f 12/346/301 11/344/300 26/354/308 27/347/302 +f 32/352/307 31/351/306 46/355/309 47/356/310 +f 33/353/25 32/352/307 47/356/310 48/357/29 +f 26/354/308 297/343/78 41/358/311 +f 27/347/302 26/354/308 41/358/311 42/359/312 +f 28/348/303 27/347/302 42/359/312 43/360/313 +f 29/349/304 28/348/303 43/360/313 44/361/314 +f 30/350/305 29/349/304 44/361/314 45/362/315 +f 31/351/306 30/350/305 45/362/315 46/355/309 +f 43/360/313 42/359/312 57/363/316 58/364/317 +f 44/361/314 43/360/313 58/364/317 59/365/318 +f 45/362/315 44/361/314 59/365/318 60/366/319 +f 46/355/309 45/362/315 60/366/319 61/367/320 +f 47/356/310 46/355/309 61/367/320 62/368/321 +f 48/357/29 47/356/310 62/368/321 63/369/40 +f 41/358/311 297/343/78 56/370/322 +f 42/359/312 41/358/311 56/370/322 57/363/316 +f 62/368/321 61/367/320 76/371/323 77/372/324 +f 63/369/40 62/368/321 77/372/324 78/373/44 +f 56/370/322 297/343/78 71/374/325 +f 57/363/316 56/370/322 71/374/325 72/375/326 +f 58/364/317 57/363/316 72/375/326 73/376/327 +f 59/365/318 58/364/317 73/376/327 74/377/328 +f 60/366/319 59/365/318 74/377/328 75/378/329 +f 61/367/320 60/366/319 75/378/329 76/371/323 +f 74/377/328 73/376/327 88/379/330 89/380/331 +f 75/378/329 74/377/328 89/380/331 90/381/332 +f 76/371/323 75/378/329 90/381/332 91/382/333 +f 77/372/324 76/371/323 91/382/333 92/383/334 +f 78/373/44 77/372/324 92/383/334 93/384/56 +f 71/374/325 297/343/78 86/385/335 +f 72/375/326 71/374/325 86/385/335 87/386/336 +f 73/376/327 72/375/326 87/386/336 88/379/330 +f 93/384/56 92/383/334 107/387/337 108/388/60 +f 86/385/335 297/343/78 101/389/338 +f 87/386/336 86/385/335 101/389/338 102/390/339 +f 88/379/330 87/386/336 102/390/339 103/391/340 +f 89/380/331 88/379/330 103/391/340 104/392/341 +f 90/381/332 89/380/331 104/392/341 105/393/342 +f 91/382/333 90/381/332 105/393/342 106/394/343 +f 92/383/334 91/382/333 106/394/343 107/387/337 +f 104/392/341 103/391/340 118/395/82 119/396/84 +f 105/393/342 104/392/341 119/396/84 120/397/86 +f 106/394/343 105/393/342 120/397/86 121/398/88 +f 107/387/337 106/394/343 121/398/88 122/399/74 +f 108/388/60 107/387/337 122/399/74 123/400/71 +f 101/389/338 297/343/78 116/401/77 +f 102/390/339 101/389/338 116/401/77 117/402/80 +f 103/391/340 102/390/339 117/402/80 118/395/82 +f 206/403/13 130/404/70 145/405/344 +f 124/406/72 123/407/71 138/408/76 139/409/345 +f 125/410/73 124/406/72 139/409/345 140/411/346 +f 126/412/66 125/410/73 140/411/346 141/413/347 +f 127/414/67 126/412/66 141/413/347 142/415/348 +f 128/416/68 127/414/67 142/415/348 143/417/349 +f 129/418/69 128/416/68 143/417/349 144/419/350 +f 130/404/70 129/418/69 144/419/350 145/405/344 +f 142/415/348 141/413/347 156/420/351 157/421/352 +f 143/417/349 142/415/348 157/421/352 158/422/353 +f 144/419/350 143/417/349 158/422/353 159/423/354 +f 145/405/344 144/419/350 159/423/354 160/424/355 +f 206/403/13 145/405/344 160/424/355 +f 139/409/345 138/408/76 153/425/94 154/426/356 +f 140/411/346 139/409/345 154/426/356 155/427/357 +f 141/413/347 140/411/346 155/427/357 156/420/351 +f 206/403/13 160/424/355 175/428/358 +f 154/426/356 153/425/94 168/429/105 169/430/359 +f 155/427/357 154/426/356 169/430/359 170/431/360 +f 156/420/351 155/427/357 170/431/360 171/432/361 +f 157/421/352 156/420/351 171/432/361 172/433/362 +f 158/422/353 157/421/352 172/433/362 173/434/363 +f 159/423/354 158/422/353 173/434/363 174/435/364 +f 160/424/355 159/423/354 174/435/364 175/428/358 +f 173/434/363 172/433/362 187/436/365 188/437/366 +f 174/435/364 173/434/363 188/437/366 189/438/367 +f 175/428/358 174/435/364 189/438/367 190/439/368 +f 206/403/13 175/428/358 190/439/368 +f 169/430/359 168/429/105 183/440/109 184/441/369 +f 170/431/360 169/430/359 184/441/369 185/442/370 +f 171/432/361 170/431/360 185/442/370 186/443/371 +f 172/433/362 171/432/361 186/443/371 187/436/365 +f 185/442/370 184/441/369 199/444/372 200/445/373 +f 186/443/371 185/442/370 200/445/373 201/446/374 +f 187/436/365 186/443/371 201/446/374 202/447/375 +f 188/437/366 187/436/365 202/447/375 203/448/376 +f 189/438/367 188/437/366 203/448/376 204/449/377 +f 190/439/368 189/438/367 204/449/377 205/450/378 +f 206/403/13 190/439/368 205/450/378 +f 184/441/369 183/440/109 198/451/121 199/444/372 +f 204/449/377 203/448/376 219/452/379 220/453/380 +f 205/450/378 204/449/377 220/453/380 221/454/381 +f 206/403/13 205/450/378 221/454/381 +f 199/444/372 198/451/121 214/455/125 215/456/382 +f 200/445/373 199/444/372 215/456/382 216/457/383 +f 201/446/374 200/445/373 216/457/383 217/458/384 +f 202/447/375 201/446/374 217/458/384 218/459/385 +f 203/448/376 202/447/375 218/459/385 219/452/379 +f 216/457/383 215/456/382 230/460/386 231/461/387 +f 217/458/384 216/457/383 231/461/387 232/462/388 +f 218/459/385 217/458/384 232/462/388 233/463/389 +f 219/452/379 218/459/385 233/463/389 234/464/390 +f 220/453/380 219/452/379 234/464/390 235/465/391 +f 221/454/381 220/453/380 235/465/391 236/466/392 +f 206/403/13 221/454/381 236/466/392 +f 215/456/382 214/455/125 229/467/136 230/460/386 +f 235/465/391 234/464/390 249/468/152 250/469/154 +f 236/466/392 235/465/391 250/469/154 251/470/156 +f 206/403/13 236/466/392 251/470/156 +f 230/460/386 229/467/136 244/471/140 245/472/158 +f 231/461/387 230/460/386 245/472/158 246/473/147 +f 232/462/388 231/461/387 246/473/147 247/474/146 +f 233/463/389 232/462/388 247/474/146 248/475/150 +f 234/464/390 233/463/389 248/475/150 249/468/152 +f 239/476/143 238/477/142 253/478/393 254/479/394 +f 240/480/144 239/476/143 254/479/394 255/481/395 +f 241/482/145 240/480/144 255/481/395 256/483/396 +f 242/484/138 241/482/145 256/483/396 257/485/397 +f 243/486/139 242/484/138 257/485/397 258/487/398 +f 244/488/140 243/486/139 258/487/398 259/489/159 +f 237/490/141 297/491/78 252/492/399 +f 238/477/142 237/490/141 252/492/399 253/478/393 +f 258/487/398 257/485/397 272/493/400 273/494/401 +f 259/489/159 258/487/398 273/494/401 274/495/163 +f 252/492/399 297/491/78 267/496/402 +f 253/478/393 252/492/399 267/496/402 268/497/403 +f 254/479/394 253/478/393 268/497/403 269/498/404 +f 255/481/395 254/479/394 269/498/404 270/499/405 +f 256/483/396 255/481/395 270/499/405 271/500/406 +f 257/485/397 256/483/396 271/500/406 272/493/400 +f 270/499/405 269/498/404 284/501/407 285/502/408 +f 271/500/406 270/499/405 285/502/408 286/503/409 +f 272/493/400 271/500/406 286/503/409 287/504/410 +f 273/494/401 272/493/400 287/504/410 288/505/411 +f 274/495/163 273/494/401 288/505/411 289/506/175 +f 267/496/402 297/491/78 282/507/412 +f 268/497/403 267/496/402 282/507/412 283/508/413 +f 269/498/404 268/497/403 283/508/413 284/501/407 +f 289/506/175 288/505/411 304/509/414 305/510/179 +f 282/507/412 297/491/78 298/511/415 +f 283/508/413 282/507/412 298/511/415 299/512/416 +f 284/501/407 283/508/413 299/512/416 300/513/417 +f 285/502/408 284/501/407 300/513/417 301/514/418 +f 286/503/409 285/502/408 301/514/418 302/515/419 +f 287/504/410 286/503/409 302/515/419 303/516/420 +f 288/505/411 287/504/410 303/516/420 304/509/414 +f 302/515/419 301/514/418 316/517/421 317/518/422 +f 303/516/420 302/515/419 317/518/422 318/519/423 +f 304/509/414 303/516/420 318/519/423 319/520/424 +f 305/510/179 304/509/414 319/520/424 320/521/190 +f 298/511/415 297/491/78 313/522/425 +f 299/512/416 298/511/415 313/522/425 314/523/426 +f 300/513/417 299/512/416 314/523/426 315/524/427 +f 301/514/418 300/513/417 315/524/427 316/517/421 +f 313/522/425 297/491/78 328/525/428 +f 314/523/426 313/522/425 328/525/428 329/526/429 +f 315/524/427 314/523/426 329/526/429 330/527/430 +f 316/517/421 315/524/427 330/527/430 331/528/431 +f 317/518/422 316/517/421 331/528/431 332/529/432 +f 318/519/423 317/518/422 332/529/432 333/530/433 +f 319/520/424 318/519/423 333/530/433 334/531/434 +f 320/521/190 319/520/424 334/531/434 335/532/194 +f 332/529/432 331/528/431 346/533/435 347/534/436 +f 333/530/433 332/529/432 347/534/436 348/535/437 +f 334/531/434 333/530/433 348/535/437 349/536/438 +f 335/532/194 334/531/434 349/536/438 350/537/205 +f 328/525/428 297/491/78 343/538/439 +f 329/526/429 328/525/428 343/538/439 344/539/440 +f 330/527/430 329/526/429 344/539/440 345/540/441 +f 331/528/431 330/527/430 345/540/441 346/533/435 +f 344/539/440 343/538/439 358/541/224 359/542/226 +f 345/540/441 344/539/440 359/542/226 360/543/228 +f 346/533/435 345/540/441 360/543/228 361/544/230 +f 347/534/436 346/533/435 361/544/230 362/545/218 +f 348/535/437 347/534/436 362/545/218 363/546/217 +f 349/536/438 348/535/437 363/546/217 364/547/221 +f 350/537/205 349/536/438 364/547/221 365/548/209 +f 343/538/439 297/491/78 358/541/224 +f 370/549/214 369/550/213 384/551/442 385/552/443 +f 371/553/215 370/549/214 385/552/443 386/554/444 +f 372/555/216 371/553/215 386/554/444 387/556/445 +f 206/557/13 372/555/216 387/556/445 +f 366/558/210 365/559/209 380/560/223 381/561/446 +f 367/562/211 366/558/210 381/561/446 382/563/447 +f 368/564/212 367/562/211 382/563/447 383/565/448 +f 369/550/213 368/564/212 383/565/448 384/551/442 +f 382/563/447 381/561/446 396/566/449 397/567/450 +f 383/565/448 382/563/447 397/567/450 398/568/451 +f 384/551/442 383/565/448 398/568/451 399/569/452 +f 385/552/443 384/551/442 399/569/452 400/570/453 +f 386/554/444 385/552/443 400/570/453 401/571/454 +f 387/556/445 386/554/444 401/571/454 402/572/455 +f 206/557/13 387/556/445 402/572/455 +f 381/561/446 380/560/223 395/573/239 396/566/449 +f 401/571/454 400/570/453 415/574/456 416/575/457 +f 402/572/455 401/571/454 416/575/457 417/576/458 +f 206/557/13 402/572/455 417/576/458 +f 396/566/449 395/573/239 410/577/243 411/578/459 +f 397/567/450 396/566/449 411/578/459 412/579/460 +f 398/568/451 397/567/450 412/579/460 413/580/461 +f 399/569/452 398/568/451 413/580/461 414/581/462 +f 400/570/453 399/569/452 414/581/462 415/574/456 +f 412/579/460 411/578/459 426/582/463 427/583/464 +f 413/580/461 412/579/460 427/583/464 428/584/465 +f 414/581/462 413/580/461 428/584/465 429/585/466 +f 415/574/456 414/581/462 429/585/466 430/586/467 +f 416/575/457 415/574/456 430/586/467 431/587/468 +f 417/576/458 416/575/457 431/587/468 432/588/469 +f 206/557/13 417/576/458 432/588/469 +f 411/578/459 410/577/243 425/589/254 426/582/463 +f 431/587/468 430/586/467 445/590/470 446/591/471 +f 432/588/469 431/587/468 446/591/471 447/592/472 +f 206/557/13 432/588/469 447/592/472 +f 426/582/463 425/589/254 440/593/258 441/594/473 +f 427/583/464 426/582/463 441/594/473 442/595/474 +f 428/584/465 427/583/464 442/595/474 443/596/475 +f 429/585/466 428/584/465 443/596/475 444/597/476 +f 430/586/467 429/585/466 444/597/476 445/590/470 +f 443/596/475 442/595/474 457/598/477 458/599/478 +f 444/597/476 443/596/475 458/599/478 459/600/479 +f 445/590/470 444/597/476 459/600/479 460/601/480 +f 446/591/471 445/590/470 460/601/480 461/602/481 +f 447/592/472 446/591/471 461/602/481 462/603/482 +f 206/557/13 447/592/472 462/603/482 +f 441/594/473 440/593/258 455/604/269 456/605/483 +f 442/595/474 441/594/473 456/605/483 457/598/477 +f 462/603/482 461/602/481 476/606/484 477/607/485 +f 206/557/13 462/603/482 477/607/485 +f 456/605/483 455/604/269 470/608/273 471/609/486 +f 457/598/477 456/605/483 471/609/486 472/610/487 +f 458/599/478 457/598/477 472/610/487 473/611/488 +f 459/600/479 458/599/478 473/611/488 474/612/489 +f 460/601/480 459/600/479 474/612/489 475/613/490 +f 461/602/481 460/601/480 475/613/490 476/606/484 +f 474/612/489 473/611/488 479/614/1 480/615/5 +f 475/613/490 474/612/489 480/615/5 10/616/7 +f 476/606/484 475/613/490 10/616/7 481/617/9 +f 477/607/485 476/606/484 481/617/9 482/618/11 +f 206/557/13 477/607/485 482/618/11 +f 471/609/486 470/608/273 8/619/15 9/620/14 +f 472/610/487 471/609/486 9/620/14 478/621/2 +f 473/611/488 472/610/487 478/621/2 479/614/1 diff --git a/tools/trenchbroom/games/Neverball/assets/__tb_info_player_start.png b/tools/trenchbroom/games/Neverball/assets/__tb_info_player_start.png new file mode 100644 index 0000000..62c7116 Binary files /dev/null and b/tools/trenchbroom/games/Neverball/assets/__tb_info_player_start.png differ diff --git a/tools/trenchbroom/games/Neverball/assets/__tb_item_health_large.obj b/tools/trenchbroom/games/Neverball/assets/__tb_item_health_large.obj new file mode 100644 index 0000000..77f4f4d --- /dev/null +++ b/tools/trenchbroom/games/Neverball/assets/__tb_item_health_large.obj @@ -0,0 +1,2066 @@ +# Blender v2.79 (sub 0) OBJ File: '__tb_info_player_start.blend' +# www.blender.org +mtllib __tb_item_health_large.mtl +o GrowSphere_Sphere +v 0.000000 0.492794 -0.073159 +v 0.000000 0.471455 -0.143506 +v 0.000000 0.436801 -0.208339 +v 0.000000 0.390165 -0.265165 +v 0.000000 0.333339 -0.311801 +v 0.000000 0.268506 -0.346455 +v 0.000000 0.198159 -0.367794 +v 0.000000 0.125000 -0.375000 +v 0.000000 0.051841 -0.367794 +v 0.000000 -0.186801 -0.208339 +v 0.014273 0.492794 -0.071753 +v 0.027997 0.471455 -0.140749 +v 0.040645 0.436801 -0.204336 +v 0.051731 0.390165 -0.260070 +v 0.060829 0.333339 -0.305810 +v 0.067590 0.268506 -0.339798 +v 0.071753 0.198159 -0.360727 +v 0.073159 0.125000 -0.367794 +v 0.071753 0.051841 -0.360727 +v 0.067590 -0.018506 -0.339798 +v 0.060829 -0.083339 -0.305810 +v 0.051731 -0.140165 -0.260070 +v 0.040645 -0.186801 -0.204336 +v 0.027997 -0.221455 -0.140749 +v 0.014273 -0.242794 -0.071753 +v 0.027997 0.492794 -0.067590 +v 0.054918 0.471455 -0.132583 +v 0.079728 0.436801 -0.192480 +v 0.101474 0.390165 -0.244981 +v 0.119321 0.333339 -0.288067 +v 0.132583 0.268506 -0.320082 +v 0.140749 0.198159 -0.339798 +v 0.143506 0.125000 -0.346455 +v 0.140749 0.051841 -0.339798 +v 0.132583 -0.018506 -0.320083 +v 0.119321 -0.083339 -0.288067 +v 0.101474 -0.140165 -0.244981 +v 0.079728 -0.186801 -0.192480 +v 0.054918 -0.221455 -0.132582 +v 0.027997 -0.242794 -0.067590 +v 0.040645 0.492794 -0.060829 +v 0.079728 0.471455 -0.119321 +v 0.115747 0.436801 -0.173227 +v 0.147318 0.390165 -0.220477 +v 0.173227 0.333339 -0.259253 +v 0.192480 0.268506 -0.288067 +v 0.204336 0.198159 -0.305810 +v 0.208339 0.125000 -0.311801 +v 0.204336 0.051841 -0.305810 +v 0.192480 -0.018506 -0.288067 +v 0.173227 -0.083339 -0.259253 +v 0.147318 -0.140165 -0.220477 +v 0.115747 -0.186801 -0.173227 +v 0.079728 -0.221455 -0.119321 +v 0.040645 -0.242794 -0.060829 +v 0.051731 0.492794 -0.051731 +v 0.101474 0.471455 -0.101474 +v 0.147318 0.436801 -0.147318 +v 0.187500 0.390165 -0.187500 +v 0.220477 0.333339 -0.220477 +v 0.244981 0.268506 -0.244980 +v 0.260070 0.198159 -0.260070 +v 0.265165 0.125000 -0.265165 +v 0.260070 0.051841 -0.260070 +v 0.244981 -0.018506 -0.244981 +v 0.220477 -0.083339 -0.220477 +v 0.187500 -0.140165 -0.187500 +v 0.147318 -0.186801 -0.147318 +v 0.101474 -0.221455 -0.101474 +v 0.051731 -0.242794 -0.051731 +v 0.060829 0.492794 -0.040645 +v 0.119321 0.471455 -0.079728 +v 0.173227 0.436801 -0.115747 +v 0.220477 0.390165 -0.147318 +v 0.259253 0.333339 -0.173227 +v 0.288067 0.268506 -0.192480 +v 0.305810 0.198159 -0.204336 +v 0.311801 0.125000 -0.208339 +v 0.305810 0.051841 -0.204336 +v 0.288067 -0.018506 -0.192480 +v 0.259253 -0.083339 -0.173227 +v 0.220477 -0.140165 -0.147318 +v 0.173227 -0.186801 -0.115747 +v 0.119321 -0.221455 -0.079728 +v 0.060829 -0.242794 -0.040645 +v 0.067590 0.492794 -0.027997 +v 0.132583 0.471455 -0.054917 +v 0.192480 0.436801 -0.079728 +v 0.244981 0.390165 -0.101474 +v 0.288067 0.333339 -0.119321 +v 0.320083 0.268506 -0.132582 +v 0.339798 0.198159 -0.140749 +v 0.346455 0.125000 -0.143506 +v 0.339798 0.051841 -0.140749 +v 0.320083 -0.018506 -0.132582 +v 0.288067 -0.083339 -0.119321 +v 0.244981 -0.140165 -0.101474 +v 0.192480 -0.186801 -0.079728 +v 0.132583 -0.221455 -0.054917 +v 0.067590 -0.242794 -0.027997 +v 0.071753 0.492794 -0.014272 +v 0.140749 0.471455 -0.027997 +v 0.204336 0.436801 -0.040645 +v 0.260070 0.390165 -0.051731 +v 0.305810 0.333339 -0.060829 +v 0.339798 0.268506 -0.067590 +v 0.360727 0.198159 -0.071753 +v 0.367795 0.125000 -0.073159 +v 0.360727 0.051841 -0.071753 +v 0.339798 -0.018506 -0.067590 +v 0.305810 -0.083339 -0.060829 +v 0.260070 -0.140165 -0.051731 +v 0.204336 -0.186801 -0.040645 +v 0.140749 -0.221455 -0.027997 +v 0.071753 -0.242794 -0.014272 +v 0.073159 0.492794 0.000000 +v 0.143506 0.471455 0.000000 +v 0.208339 0.436801 0.000000 +v 0.265165 0.390165 0.000000 +v 0.311801 0.333339 0.000000 +v 0.346455 0.268506 0.000000 +v 0.367794 0.198159 0.000000 +v 0.375000 0.125000 0.000000 +v 0.367794 0.051841 0.000000 +v 0.346455 -0.018506 0.000000 +v 0.311801 -0.083339 0.000000 +v 0.265165 -0.140165 0.000000 +v 0.208339 -0.186801 0.000000 +v 0.143506 -0.221455 0.000000 +v 0.073159 -0.242794 0.000000 +v 0.071753 0.492794 0.014273 +v 0.140749 0.471455 0.027997 +v 0.204336 0.436801 0.040645 +v 0.260070 0.390165 0.051731 +v 0.305810 0.333339 0.060830 +v 0.339798 0.268506 0.067590 +v 0.360727 0.198159 0.071753 +v 0.367795 0.125000 0.073159 +v 0.360727 0.051841 0.071753 +v 0.339798 -0.018506 0.067590 +v 0.305810 -0.083339 0.060830 +v 0.260070 -0.140165 0.051731 +v 0.204336 -0.186801 0.040645 +v 0.140749 -0.221455 0.027997 +v 0.071753 -0.242794 0.014273 +v 0.067590 0.492794 0.027997 +v 0.132583 0.471455 0.054918 +v 0.192480 0.436801 0.079728 +v 0.244981 0.390165 0.101474 +v 0.288067 0.333339 0.119321 +v 0.320083 0.268506 0.132583 +v 0.339798 0.198159 0.140749 +v 0.346455 0.125000 0.143506 +v 0.339798 0.051841 0.140749 +v 0.320083 -0.018506 0.132583 +v 0.288067 -0.083339 0.119321 +v 0.244981 -0.140165 0.101474 +v 0.192480 -0.186801 0.079728 +v 0.132583 -0.221455 0.054918 +v 0.067590 -0.242794 0.027997 +v 0.060829 0.492794 0.040645 +v 0.119321 0.471455 0.079728 +v 0.173227 0.436801 0.115747 +v 0.220477 0.390165 0.147318 +v 0.259253 0.333339 0.173228 +v 0.288067 0.268506 0.192480 +v 0.305810 0.198159 0.204336 +v 0.311801 0.125000 0.208339 +v 0.305810 0.051841 0.204336 +v 0.288067 -0.018506 0.192480 +v 0.259253 -0.083339 0.173228 +v 0.220477 -0.140165 0.147318 +v 0.173227 -0.186801 0.115747 +v 0.119321 -0.221455 0.079728 +v 0.060829 -0.242794 0.040645 +v 0.051731 0.492794 0.051731 +v 0.101474 0.471455 0.101474 +v 0.147318 0.436801 0.147318 +v 0.187500 0.390165 0.187500 +v 0.220477 0.333339 0.220477 +v 0.244981 0.268506 0.244981 +v 0.260070 0.198159 0.260070 +v 0.265165 0.125000 0.265165 +v 0.260070 0.051841 0.260070 +v 0.244981 -0.018506 0.244981 +v 0.220477 -0.083339 0.220477 +v 0.187500 -0.140165 0.187500 +v 0.147318 -0.186801 0.147318 +v 0.101474 -0.221455 0.101474 +v 0.051731 -0.242794 0.051731 +v 0.040645 0.492794 0.060830 +v 0.079728 0.471455 0.119321 +v 0.115747 0.436801 0.173228 +v 0.147318 0.390165 0.220477 +v 0.173227 0.333339 0.259253 +v 0.192480 0.268506 0.288067 +v 0.204336 0.198159 0.305810 +v 0.208339 0.125000 0.311801 +v 0.204336 0.051841 0.305810 +v 0.192480 -0.018506 0.288067 +v 0.173227 -0.083339 0.259253 +v 0.147318 -0.140165 0.220477 +v 0.115747 -0.186801 0.173228 +v 0.079728 -0.221455 0.119321 +v 0.040645 -0.242794 0.060830 +v 0.000000 -0.250000 0.000000 +v 0.027997 0.492794 0.067590 +v 0.054918 0.471455 0.132583 +v 0.079728 0.436801 0.192480 +v 0.101474 0.390165 0.244981 +v 0.119321 0.333339 0.288067 +v 0.132583 0.268506 0.320083 +v 0.140749 0.198159 0.339798 +v 0.143506 0.125000 0.346455 +v 0.140749 0.051841 0.339798 +v 0.132583 -0.018506 0.320083 +v 0.119321 -0.083339 0.288067 +v 0.101474 -0.140165 0.244981 +v 0.079728 -0.186801 0.192480 +v 0.054917 -0.221455 0.132583 +v 0.027997 -0.242794 0.067590 +v 0.014273 0.492794 0.071753 +v 0.027997 0.471455 0.140749 +v 0.040645 0.436801 0.204336 +v 0.051731 0.390165 0.260070 +v 0.060829 0.333339 0.305810 +v 0.067590 0.268506 0.339798 +v 0.071753 0.198159 0.360727 +v 0.073159 0.125000 0.367795 +v 0.071753 0.051841 0.360727 +v 0.067590 -0.018506 0.339798 +v 0.060829 -0.083339 0.305810 +v 0.051731 -0.140165 0.260070 +v 0.040645 -0.186801 0.204336 +v 0.027997 -0.221455 0.140749 +v 0.014273 -0.242794 0.071753 +v -0.000000 0.492794 0.073159 +v 0.000000 0.471455 0.143506 +v 0.000000 0.436801 0.208339 +v -0.000000 0.390165 0.265165 +v -0.000000 0.333339 0.311801 +v 0.000000 0.268506 0.346455 +v -0.000000 0.198159 0.367795 +v -0.000000 0.125000 0.375000 +v -0.000000 0.051841 0.367795 +v 0.000000 -0.018506 0.346455 +v -0.000000 -0.083339 0.311801 +v -0.000000 -0.140165 0.265165 +v -0.000000 -0.186801 0.208339 +v 0.000000 -0.221455 0.143506 +v 0.000000 -0.242794 0.073159 +v -0.014273 0.492794 0.071753 +v -0.027997 0.471455 0.140749 +v -0.040645 0.436801 0.204336 +v -0.051731 0.390165 0.260070 +v -0.060829 0.333339 0.305810 +v -0.067590 0.268506 0.339798 +v -0.071753 0.198159 0.360727 +v -0.073159 0.125000 0.367795 +v -0.071753 0.051841 0.360727 +v -0.067590 -0.018506 0.339798 +v -0.060829 -0.083339 0.305810 +v -0.051731 -0.140165 0.260070 +v -0.040645 -0.186801 0.204336 +v -0.027997 -0.221455 0.140749 +v -0.014273 -0.242794 0.071753 +v -0.027997 0.492794 0.067590 +v -0.054917 0.471455 0.132583 +v -0.079728 0.436801 0.192480 +v -0.101474 0.390165 0.244981 +v -0.119321 0.333339 0.288067 +v -0.132583 0.268506 0.320083 +v -0.140749 0.198159 0.339798 +v -0.143506 0.125000 0.346455 +v -0.140749 0.051841 0.339798 +v -0.132583 -0.018506 0.320083 +v -0.119321 -0.083339 0.288067 +v -0.101474 -0.140165 0.244981 +v -0.079728 -0.186801 0.192480 +v -0.054917 -0.221455 0.132583 +v -0.027997 -0.242794 0.067590 +v -0.040645 0.492794 0.060830 +v -0.079728 0.471455 0.119321 +v -0.115747 0.436801 0.173228 +v -0.147318 0.390165 0.220477 +v -0.173227 0.333339 0.259253 +v -0.192480 0.268506 0.288067 +v -0.204336 0.198159 0.305810 +v -0.208339 0.125000 0.311801 +v -0.204336 0.051841 0.305810 +v -0.192480 -0.018506 0.288067 +v -0.173227 -0.083339 0.259253 +v -0.147318 -0.140165 0.220477 +v -0.115747 -0.186801 0.173227 +v -0.079728 -0.221455 0.119321 +v -0.040645 -0.242794 0.060829 +v -0.000000 0.500000 0.000000 +v -0.051731 0.492794 0.051731 +v -0.101474 0.471455 0.101474 +v -0.147318 0.436801 0.147318 +v -0.187500 0.390165 0.187500 +v -0.220477 0.333339 0.220477 +v -0.244981 0.268506 0.244981 +v -0.260070 0.198159 0.260070 +v -0.265165 0.125000 0.265165 +v -0.260070 0.051841 0.260070 +v -0.244981 -0.018506 0.244981 +v -0.220477 -0.083339 0.220477 +v -0.187500 -0.140165 0.187500 +v -0.147318 -0.186801 0.147318 +v -0.101474 -0.221455 0.101474 +v -0.051731 -0.242794 0.051731 +v -0.060829 0.492794 0.040645 +v -0.119321 0.471455 0.079728 +v -0.173227 0.436801 0.115747 +v -0.220477 0.390165 0.147318 +v -0.259253 0.333339 0.173227 +v -0.288067 0.268506 0.192480 +v -0.305810 0.198159 0.204336 +v -0.311801 0.125000 0.208339 +v -0.305810 0.051841 0.204336 +v -0.288067 -0.018506 0.192480 +v -0.259253 -0.083339 0.173227 +v -0.220477 -0.140165 0.147318 +v -0.173227 -0.186801 0.115747 +v -0.119321 -0.221455 0.079728 +v -0.060829 -0.242794 0.040645 +v -0.067590 0.492794 0.027997 +v -0.132583 0.471455 0.054918 +v -0.192480 0.436801 0.079728 +v -0.244981 0.390165 0.101474 +v -0.288067 0.333339 0.119321 +v -0.320083 0.268506 0.132583 +v -0.339798 0.198159 0.140749 +v -0.346455 0.125000 0.143506 +v -0.339798 0.051841 0.140749 +v -0.320083 -0.018506 0.132583 +v -0.288067 -0.083339 0.119321 +v -0.244981 -0.140165 0.101474 +v -0.192480 -0.186801 0.079728 +v -0.132582 -0.221455 0.054918 +v -0.067590 -0.242794 0.027997 +v -0.071753 0.492794 0.014273 +v -0.140749 0.471455 0.027997 +v -0.204336 0.436801 0.040645 +v -0.260070 0.390165 0.051731 +v -0.305810 0.333339 0.060829 +v -0.339798 0.268506 0.067590 +v -0.360727 0.198159 0.071753 +v -0.367794 0.125000 0.073159 +v -0.360727 0.051841 0.071753 +v -0.339798 -0.018506 0.067590 +v -0.305810 -0.083339 0.060829 +v -0.260070 -0.140165 0.051731 +v -0.204336 -0.186801 0.040645 +v -0.140749 -0.221455 0.027997 +v -0.071753 -0.242794 0.014273 +v -0.073159 0.492794 0.000000 +v -0.143506 0.471455 0.000000 +v -0.208339 0.436801 0.000000 +v -0.265165 0.390165 0.000000 +v -0.311801 0.333339 0.000000 +v -0.346455 0.268506 0.000000 +v -0.367794 0.198159 0.000000 +v -0.375000 0.125000 0.000000 +v -0.367794 0.051841 0.000000 +v -0.346455 -0.018506 0.000000 +v -0.311801 -0.083339 0.000000 +v -0.265165 -0.140165 0.000000 +v -0.208339 -0.186801 0.000000 +v -0.143506 -0.221455 0.000000 +v -0.073159 -0.242794 0.000000 +v -0.071753 0.492794 -0.014272 +v -0.140749 0.471455 -0.027997 +v -0.204336 0.436801 -0.040645 +v -0.260070 0.390165 -0.051731 +v -0.305810 0.333339 -0.060829 +v -0.339798 0.268506 -0.067590 +v -0.360727 0.198159 -0.071753 +v -0.367794 0.125000 -0.073159 +v -0.360727 0.051841 -0.071753 +v -0.339798 -0.018506 -0.067590 +v -0.305810 -0.083339 -0.060829 +v -0.260070 -0.140165 -0.051731 +v -0.204336 -0.186801 -0.040645 +v -0.140749 -0.221455 -0.027997 +v -0.071753 -0.242794 -0.014272 +v -0.067590 0.492794 -0.027997 +v -0.132583 0.471455 -0.054917 +v -0.192480 0.436801 -0.079728 +v -0.244980 0.390165 -0.101474 +v -0.288066 0.333339 -0.119321 +v -0.320082 0.268506 -0.132582 +v -0.339798 0.198159 -0.140749 +v -0.346455 0.125000 -0.143506 +v -0.339798 0.051841 -0.140749 +v -0.320082 -0.018506 -0.132582 +v -0.288066 -0.083339 -0.119321 +v -0.244980 -0.140165 -0.101474 +v -0.192480 -0.186801 -0.079728 +v -0.132582 -0.221455 -0.054917 +v -0.067590 -0.242794 -0.027997 +v -0.060829 0.492794 -0.040645 +v -0.119321 0.471455 -0.079728 +v -0.173227 0.436801 -0.115747 +v -0.220477 0.390165 -0.147318 +v -0.259253 0.333339 -0.173227 +v -0.288067 0.268506 -0.192480 +v -0.305810 0.198159 -0.204336 +v -0.311801 0.125000 -0.208339 +v -0.305810 0.051841 -0.204336 +v -0.288067 -0.018506 -0.192480 +v -0.259253 -0.083339 -0.173227 +v -0.220477 -0.140165 -0.147318 +v -0.173227 -0.186801 -0.115747 +v -0.119321 -0.221455 -0.079728 +v -0.060829 -0.242794 -0.040645 +v -0.051731 0.492794 -0.051731 +v -0.101474 0.471455 -0.101474 +v -0.147318 0.436801 -0.147318 +v -0.187500 0.390165 -0.187500 +v -0.220476 0.333339 -0.220477 +v -0.244981 0.268506 -0.244980 +v -0.260070 0.198159 -0.260070 +v -0.265165 0.125000 -0.265165 +v -0.260070 0.051841 -0.260070 +v -0.244981 -0.018506 -0.244980 +v -0.220476 -0.083339 -0.220477 +v -0.187500 -0.140165 -0.187500 +v -0.147318 -0.186801 -0.147318 +v -0.101474 -0.221455 -0.101474 +v -0.051731 -0.242794 -0.051731 +v -0.040645 0.492794 -0.060829 +v -0.079728 0.471455 -0.119321 +v -0.115747 0.436801 -0.173227 +v -0.147318 0.390165 -0.220477 +v -0.173227 0.333339 -0.259253 +v -0.192480 0.268506 -0.288067 +v -0.204335 0.198159 -0.305810 +v -0.208339 0.125000 -0.311801 +v -0.204335 0.051841 -0.305810 +v -0.192480 -0.018506 -0.288067 +v -0.173227 -0.083339 -0.259253 +v -0.147318 -0.140165 -0.220477 +v -0.115747 -0.186801 -0.173227 +v -0.079728 -0.221455 -0.119321 +v -0.040645 -0.242794 -0.060829 +v -0.027997 0.492794 -0.067590 +v -0.054917 0.471455 -0.132582 +v -0.079728 0.436801 -0.192480 +v -0.101474 0.390165 -0.244980 +v -0.119321 0.333339 -0.288066 +v -0.132582 0.268506 -0.320082 +v -0.140749 0.198159 -0.339797 +v -0.143506 0.125000 -0.346455 +v -0.140749 0.051841 -0.339797 +v -0.132582 -0.018506 -0.320082 +v -0.119321 -0.083339 -0.288066 +v -0.101474 -0.140165 -0.244980 +v -0.079728 -0.186801 -0.192480 +v -0.054917 -0.221455 -0.132582 +v -0.027997 -0.242794 -0.067590 +v -0.014273 0.492794 -0.071753 +v -0.027997 0.471455 -0.140749 +v -0.040645 0.436801 -0.204335 +v -0.051731 0.390165 -0.260070 +v -0.060829 0.333339 -0.305810 +v -0.067590 0.268506 -0.339798 +v -0.071753 0.198159 -0.360727 +v -0.073159 0.125000 -0.367794 +v -0.071753 0.051841 -0.360727 +v -0.067590 -0.018506 -0.339798 +v -0.060829 -0.083339 -0.305810 +v -0.051731 -0.140165 -0.260070 +v -0.040645 -0.186801 -0.204335 +v -0.027997 -0.221455 -0.140749 +v -0.014273 -0.242794 -0.071753 +v 0.000000 -0.018506 -0.346455 +v 0.000000 -0.083339 -0.311801 +v 0.000000 -0.140165 -0.265165 +v 0.000000 -0.221455 -0.143506 +v 0.000000 -0.242794 -0.073159 +vt 0.668772 0.339905 +vt 0.689230 0.360743 +vt 0.669184 0.377746 +vt 0.651681 0.356229 +vt 0.389163 0.202579 +vt 0.362996 0.217196 +vt 0.354467 0.203069 +vt 0.377271 0.185807 +vt 0.646681 0.320659 +vt 0.633008 0.335578 +vt 0.413677 0.185991 +vt 0.398545 0.167533 +vt 0.622926 0.303143 +vt 0.612891 0.315762 +vt 0.436588 0.167587 +vt 0.418601 0.148246 +vt 0.597548 0.287432 +vt 0.591132 0.296771 +vt 0.458023 0.147603 +vt 0.437837 0.127926 +vt 0.570644 0.273504 +vt 0.567617 0.278601 +vt 0.478275 0.126406 +vt 0.456847 0.106512 +vt 0.305589 0.240241 +vt 0.274071 0.248522 +vt 0.303203 0.234492 +vt 0.542292 0.261250 +vt 0.708194 0.382963 +vt 0.726005 0.406260 +vt 0.702401 0.423755 +vt 0.685896 0.400205 +vt 0.335155 0.229756 +vt 0.329861 0.219303 +vt 0.663172 0.415515 +vt 0.648629 0.392409 +vt 0.323071 0.210092 +vt 0.344338 0.190783 +vt 0.633758 0.370044 +vt 0.363989 0.171294 +vt 0.618149 0.348117 +vt 0.382403 0.151482 +vt 0.601457 0.326404 +vt 0.399978 0.131162 +vt 0.583389 0.304743 +vt 0.417177 0.110087 +vt 0.563718 0.283032 +vt 0.434588 0.087911 +vt 0.299830 0.229324 +vt 0.677930 0.439801 +vt 0.588867 0.335092 +vt 0.574555 0.311248 +vt 0.380492 0.116148 +vt 0.395679 0.094118 +vt 0.559087 0.286667 +vt 0.411285 0.070977 +vt 0.295606 0.224884 +vt 0.652447 0.453972 +vt 0.639692 0.428795 +vt 0.315020 0.202234 +vt 0.627341 0.404858 +vt 0.332858 0.180314 +vt 0.614973 0.381555 +vt 0.349473 0.158868 +vt 0.602248 0.358424 +vt 0.365227 0.137595 +vt 0.305914 0.195823 +vt 0.320206 0.171664 +vt 0.605219 0.415133 +vt 0.595309 0.390853 +vt 0.333813 0.148443 +vt 0.585400 0.366570 +vt 0.346997 0.125748 +vt 0.575302 0.341820 +vt 0.360029 0.103127 +vt 0.564843 0.316200 +vt 0.373209 0.080066 +vt 0.553878 0.289397 +vt 0.386907 0.055924 +vt 0.290677 0.221292 +vt 0.625970 0.466029 +vt 0.615350 0.439958 +vt 0.338534 0.092053 +vt 0.349744 0.067938 +vt 0.554450 0.319516 +vt 0.548253 0.291138 +vt 0.361527 0.042845 +vt 0.285201 0.218644 +vt 0.598611 0.475863 +vt 0.590142 0.448972 +vt 0.295936 0.190947 +vt 0.582222 0.423250 +vt 0.306517 0.164866 +vt 0.574753 0.397969 +vt 0.317063 0.139995 +vt 0.567667 0.372561 +vt 0.327692 0.115886 +vt 0.560912 0.346549 +vt 0.558307 0.429239 +vt 0.553277 0.402895 +vt 0.291900 0.159996 +vt 0.299242 0.133555 +vt 0.549089 0.376349 +vt 0.307269 0.107991 +vt 0.545827 0.349198 +vt 0.315959 0.082871 +vt 0.543571 0.321107 +vt 0.325296 0.057677 +vt 0.542388 0.291828 +vt 0.335284 0.031720 +vt 0.279342 0.217017 +vt 0.570531 0.483497 +vt 0.564093 0.455881 +vt 0.285266 0.187700 +vt 0.532418 0.320875 +vt 0.536469 0.291426 +vt 0.299855 0.049111 +vt 0.308360 0.022381 +vt 0.273275 0.216467 +vt 0.541920 0.489120 +vt 0.537178 0.460846 +vt 0.274090 0.186190 +vt 0.533366 0.433155 +vt 0.276456 0.157179 +vt 0.530795 0.405581 +vt 0.280338 0.129215 +vt 0.529677 0.377815 +vt 0.285630 0.102075 +vt 0.530176 0.349635 +vt 0.292196 0.075493 +vt 0.260296 0.156605 +vt 0.260296 0.127156 +vt 0.507124 0.405903 +vt 0.509417 0.376745 +vt 0.262576 0.098207 +vt 0.514114 0.347662 +vt 0.266993 0.069785 +vt 0.521233 0.318712 +vt 0.273284 0.041887 +vt 0.530693 0.289920 +vt 0.280981 0.014424 +vt 0.267186 0.217028 +vt 0.512983 0.493192 +vt 0.509189 0.464218 +vt 0.262617 0.186536 +vt 0.507124 0.435075 +vt 0.478275 0.389352 +vt 0.458023 0.410549 +vt 0.437837 0.390872 +vt 0.456847 0.369458 +vt 0.305590 0.503188 +vt 0.274071 0.511469 +vt 0.303203 0.497438 +vt 0.478275 0.575178 +vt 0.466108 0.603512 +vt 0.461011 0.600503 +vt 0.357244 0.741258 +vt 0.334067 0.759173 +vt 0.316446 0.735681 +vt 0.339906 0.719060 +vt 0.335155 0.492703 +vt 0.329861 0.482249 +vt 0.379353 0.722215 +vt 0.362280 0.702258 +vt 0.362996 0.480142 +vt 0.354467 0.466015 +vt 0.400085 0.701700 +vt 0.383716 0.684686 +vt 0.389163 0.465525 +vt 0.377271 0.448753 +vt 0.419231 0.679571 +vt 0.404285 0.665961 +vt 0.413677 0.448937 +vt 0.398545 0.430479 +vt 0.436650 0.655795 +vt 0.424019 0.645809 +vt 0.436588 0.430533 +vt 0.418601 0.411192 +vt 0.452269 0.630411 +vt 0.442927 0.624028 +vt 0.369847 0.666822 +vt 0.391713 0.651154 +vt 0.363990 0.434240 +vt 0.382403 0.414428 +vt 0.413358 0.634418 +vt 0.399978 0.394108 +vt 0.434946 0.616316 +vt 0.417176 0.373033 +vt 0.456578 0.596621 +vt 0.434588 0.350856 +vt 0.299830 0.492271 +vt 0.300261 0.711288 +vt 0.324490 0.696407 +vt 0.323071 0.473038 +vt 0.347540 0.681767 +vt 0.344338 0.453729 +vt 0.452938 0.592006 +vt 0.285945 0.685844 +vt 0.311102 0.672966 +vt 0.295606 0.487831 +vt 0.315021 0.465181 +vt 0.335012 0.660520 +vt 0.332858 0.443260 +vt 0.358281 0.648079 +vt 0.349473 0.421814 +vt 0.381368 0.635294 +vt 0.365227 0.400541 +vt 0.404647 0.621863 +vt 0.380492 0.379094 +vt 0.428428 0.607510 +vt 0.395678 0.357064 +vt 0.411284 0.333923 +vt 0.373184 0.618476 +vt 0.397893 0.608329 +vt 0.346997 0.388694 +vt 0.360029 0.366073 +vt 0.423460 0.597822 +vt 0.373209 0.343012 +vt 0.450200 0.586811 +vt 0.386906 0.318870 +vt 0.290678 0.484238 +vt 0.273749 0.659366 +vt 0.299836 0.648633 +vt 0.305914 0.458770 +vt 0.324662 0.638417 +vt 0.320206 0.434610 +vt 0.348930 0.628440 +vt 0.333813 0.411389 +vt 0.285201 0.481590 +vt 0.295937 0.453893 +vt 0.290734 0.623405 +vt 0.316479 0.615416 +vt 0.306517 0.427812 +vt 0.341772 0.607897 +vt 0.317063 0.402941 +vt 0.367159 0.600767 +vt 0.327692 0.378832 +vt 0.393137 0.593964 +vt 0.338534 0.355000 +vt 0.420125 0.587451 +vt 0.349744 0.330884 +vt 0.448449 0.581199 +vt 0.361527 0.305791 +vt 0.263791 0.631962 +vt 0.307269 0.370937 +vt 0.315958 0.345818 +vt 0.390461 0.578901 +vt 0.418512 0.576591 +vt 0.325296 0.320623 +vt 0.447747 0.575345 +vt 0.335283 0.294666 +vt 0.279342 0.479964 +vt 0.256065 0.603793 +vt 0.283767 0.597314 +vt 0.285267 0.450647 +vt 0.310443 0.591495 +vt 0.291900 0.422942 +vt 0.336815 0.586433 +vt 0.299242 0.396501 +vt 0.363341 0.582209 +vt 0.278797 0.570347 +vt 0.306518 0.566554 +vt 0.274090 0.449137 +vt 0.276456 0.420125 +vt 0.334106 0.563971 +vt 0.280338 0.392161 +vt 0.361847 0.562818 +vt 0.285630 0.365021 +vt 0.389996 0.563270 +vt 0.292195 0.338439 +vt 0.418721 0.565454 +vt 0.299855 0.312058 +vt 0.448135 0.569434 +vt 0.308359 0.285328 +vt 0.273275 0.479414 +vt 0.250405 0.575044 +vt 0.391939 0.547227 +vt 0.420859 0.554281 +vt 0.266993 0.332732 +vt 0.273284 0.304833 +vt 0.449626 0.563665 +vt 0.280980 0.277371 +vt 0.267187 0.479974 +vt 0.246401 0.545909 +vt 0.275509 0.542335 +vt 0.262617 0.449483 +vt 0.304623 0.540317 +vt 0.260296 0.419552 +vt 0.333769 0.540318 +vt 0.260296 0.390103 +vt 0.362891 0.542580 +vt 0.262575 0.361154 +vt 0.761811 0.347681 +vt 0.768908 0.318727 +vt 0.780094 0.320881 +vt 0.777874 0.349643 +vt 0.564347 0.675320 +vt 0.543898 0.654488 +vt 0.563946 0.637492 +vt 0.581435 0.658999 +vt 0.757134 0.376765 +vt 0.777395 0.377824 +vt 0.586437 0.694569 +vt 0.600112 0.679650 +vt 0.754853 0.405922 +vt 0.778527 0.405595 +vt 0.610192 0.712088 +vt 0.620229 0.699470 +vt 0.754853 0.435093 +vt 0.781108 0.433185 +vt 0.635570 0.727802 +vt 0.641987 0.718463 +vt 0.756891 0.464239 +vt 0.784920 0.460921 +vt 0.662473 0.741731 +vt 0.665500 0.736635 +vt 0.760508 0.493374 +vt 0.789651 0.489316 +vt 0.778345 0.289928 +vt 0.789919 0.261250 +vt 0.784121 0.291430 +vt 0.690823 0.753987 +vt 0.524935 0.632265 +vt 0.507124 0.608964 +vt 0.530732 0.591469 +vt 0.547237 0.615024 +vt 0.806069 0.429255 +vt 0.811888 0.455932 +vt 0.649731 0.710492 +vt 0.669399 0.732204 +vt 0.818384 0.483616 +vt 0.790041 0.291827 +vt 0.555208 0.575421 +vt 0.569968 0.599712 +vt 0.791247 0.321105 +vt 0.584515 0.622824 +vt 0.793525 0.349194 +vt 0.599366 0.645177 +vt 0.796808 0.376345 +vt 0.614975 0.667111 +vt 0.801016 0.402895 +vt 0.631664 0.688828 +vt 0.605807 0.610369 +vt 0.618159 0.633668 +vt 0.808608 0.346533 +vt 0.815385 0.372542 +vt 0.630879 0.656805 +vt 0.822496 0.397949 +vt 0.644257 0.680142 +vt 0.829996 0.423234 +vt 0.658565 0.703988 +vt 0.837962 0.448965 +vt 0.674030 0.728570 +vt 0.846513 0.475871 +vt 0.795905 0.291132 +vt 0.580696 0.561249 +vt 0.593452 0.586430 +vt 0.802124 0.319505 +vt 0.668278 0.699037 +vt 0.679240 0.725841 +vt 0.863157 0.439887 +vt 0.873856 0.465923 +vt 0.801527 0.289386 +vt 0.607176 0.549193 +vt 0.617796 0.575265 +vt 0.812514 0.316180 +vt 0.627928 0.600091 +vt 0.822994 0.341792 +vt 0.637829 0.624374 +vt 0.833114 0.366534 +vt 0.647731 0.648663 +vt 0.843047 0.390809 +vt 0.657823 0.673416 +vt 0.852991 0.415079 +vt 0.658390 0.617269 +vt 0.665465 0.642677 +vt 0.849954 0.358372 +vt 0.862699 0.381487 +vt 0.672213 0.668690 +vt 0.875090 0.404766 +vt 0.678671 0.695722 +vt 0.887452 0.428664 +vt 0.684864 0.724100 +vt 0.900261 0.453770 +vt 0.806735 0.286652 +vt 0.634536 0.539361 +vt 0.643004 0.566251 +vt 0.822222 0.311220 +vt 0.650928 0.591972 +vt 0.836553 0.335052 +vt 0.811362 0.283014 +vt 0.690729 0.723410 +vt 0.662613 0.531730 +vt 0.669050 0.559341 +vt 0.831050 0.304708 +vt 0.674839 0.585978 +vt 0.849136 0.326354 +vt 0.679866 0.612354 +vt 0.865844 0.348051 +vt 0.684042 0.638896 +vt 0.881467 0.369960 +vt 0.687298 0.666044 +vt 0.896347 0.392297 +vt 0.689549 0.694133 +vt 0.910870 0.415352 +vt 0.925629 0.439546 +vt 0.880692 0.335502 +vt 0.899375 0.356137 +vt 0.703451 0.637435 +vt 0.702946 0.665609 +vt 0.916877 0.377637 +vt 0.700701 0.694366 +vt 0.933539 0.400050 +vt 0.696648 0.723813 +vt 0.949961 0.423523 +vt 0.815258 0.278580 +vt 0.691218 0.526109 +vt 0.695958 0.554375 +vt 0.838787 0.296729 +vt 0.699773 0.582056 +vt 0.860562 0.315703 +vt 0.702344 0.609678 +vt 0.720145 0.522040 +vt 0.723936 0.551005 +vt 0.818280 0.273480 +vt 0.845196 0.287385 +vt 0.725999 0.580136 +vt 0.870586 0.303076 +vt 0.725999 0.609363 +vt 0.894356 0.320575 +vt 0.723704 0.638508 +vt 0.916459 0.339810 +vt 0.719005 0.667584 +vt 0.936922 0.360645 +vt 0.711884 0.696530 +vt 0.955850 0.382862 +vt 0.702423 0.725319 +vt 0.973431 0.406172 +vt 0.599044 0.014424 +vt 0.628498 0.014424 +vt 0.626437 0.034472 +vt 0.598469 0.030587 +vt 0.189946 0.171162 +vt 0.167327 0.188875 +vt 0.152666 0.170621 +vt 0.172639 0.151935 +vt 0.569110 0.016746 +vt 0.569456 0.028219 +vt 0.211232 0.152027 +vt 0.191935 0.132356 +vt 0.538618 0.021316 +vt 0.539178 0.027405 +vt 0.231447 0.131881 +vt 0.211109 0.111861 +vt 0.061469 0.242777 +vt 0.030595 0.252304 +vt 0.058935 0.237166 +vt 0.507124 0.028202 +vt 0.713744 0.027395 +vt 0.741217 0.035092 +vt 0.733260 0.062481 +vt 0.706520 0.053978 +vt 0.090334 0.231872 +vt 0.084975 0.221653 +vt 0.685832 0.021104 +vt 0.680127 0.046323 +vt 0.117564 0.219306 +vt 0.109119 0.205449 +vt 0.657458 0.016705 +vt 0.653584 0.039773 +vt 0.143219 0.204965 +vt 0.131596 0.188451 +vt 0.055439 0.232139 +vt 0.078137 0.212633 +vt 0.697957 0.079428 +vt 0.672754 0.070095 +vt 0.099071 0.193344 +vt 0.647660 0.061415 +vt 0.118548 0.174069 +vt 0.622094 0.053379 +vt 0.136924 0.154618 +vt 0.595651 0.046032 +vt 0.154589 0.134786 +vt 0.567945 0.039396 +vt 0.172025 0.114329 +vt 0.538628 0.033472 +vt 0.189792 0.092919 +vt 0.723921 0.089414 +vt 0.120057 0.140650 +vt 0.135553 0.119561 +vt 0.590779 0.060649 +vt 0.564698 0.050066 +vt 0.151126 0.098002 +vt 0.537002 0.039331 +vt 0.167257 0.075451 +vt 0.051111 0.227840 +vt 0.712797 0.115663 +vt 0.687699 0.103882 +vt 0.070041 0.204930 +vt 0.663578 0.092677 +vt 0.087646 0.182986 +vt 0.639757 0.081836 +vt 0.104208 0.161672 +vt 0.615649 0.071200 +vt 0.675575 0.127351 +vt 0.652510 0.114176 +vt 0.060878 0.198647 +vt 0.075006 0.174391 +vt 0.629889 0.101138 +vt 0.088649 0.151197 +vt 0.607197 0.087948 +vt 0.102027 0.128623 +vt 0.583980 0.074337 +vt 0.115399 0.106210 +vt 0.559822 0.060043 +vt 0.129082 0.083446 +vt 0.534354 0.044807 +vt 0.143445 0.059697 +vt 0.046092 0.224391 +vt 0.699719 0.141045 +vt 0.575328 0.086988 +vt 0.553411 0.069149 +vt 0.094059 0.094708 +vt 0.105856 0.070698 +vt 0.530762 0.049736 +vt 0.118411 0.045782 +vt 0.040536 0.221892 +vt 0.684668 0.165423 +vt 0.661528 0.149822 +vt 0.050824 0.193883 +vt 0.639496 0.134643 +vt 0.061274 0.167614 +vt 0.618037 0.119363 +vt 0.071908 0.142643 +vt 0.596769 0.103605 +vt 0.082798 0.118505 +vt 0.624491 0.154131 +vt 0.604145 0.136532 +vt 0.046550 0.162751 +vt 0.053993 0.136069 +vt 0.584342 0.118117 +vt 0.062309 0.110309 +vt 0.564860 0.098465 +vt 0.071461 0.085035 +vt 0.545554 0.077199 +vt 0.081442 0.059742 +vt 0.526322 0.053960 +vt 0.092269 0.033725 +vt 0.034607 0.220421 +vt 0.667740 0.188724 +vt 0.645566 0.171320 +vt 0.040051 0.190748 +vt 0.536344 0.083989 +vt 0.521155 0.057333 +vt 0.055798 0.050439 +vt 0.065182 0.023397 +vt 0.028480 0.220039 +vt 0.649146 0.210979 +vt 0.627736 0.191978 +vt 0.028743 0.189363 +vt 0.607418 0.172754 +vt 0.030929 0.159948 +vt 0.588093 0.152664 +vt 0.034881 0.131594 +vt 0.569830 0.131393 +vt 0.040449 0.104080 +vt 0.552575 0.108592 +vt 0.047477 0.077142 +vt 0.014424 0.159388 +vt 0.014424 0.129394 +vt 0.569644 0.167783 +vt 0.553064 0.143280 +vt 0.016940 0.099886 +vt 0.538450 0.117119 +vt 0.021811 0.070899 +vt 0.525891 0.089282 +vt 0.028776 0.042442 +vt 0.515406 0.059719 +vt 0.037375 0.014424 +vt 0.022300 0.220775 +vt 0.629261 0.232402 +vt 0.608070 0.212158 +vt 0.017030 0.189838 +vt 0.588093 0.190735 +vn 0.0000 -0.5528 -0.8333 +vn 0.0000 -0.3805 -0.9247 +vn 0.1804 -0.3805 -0.9070 +vn 0.1626 -0.5528 -0.8173 +vn 0.0000 0.7040 -0.7101 +vn 0.0000 0.8286 -0.5598 +vn 0.1092 0.8286 -0.5490 +vn 0.1385 0.7040 -0.6965 +vn 0.0000 -0.7040 -0.7101 +vn 0.1385 -0.7040 -0.6965 +vn 0.0000 0.5528 -0.8333 +vn 0.1626 0.5528 -0.8173 +vn 0.0000 -0.8286 -0.5598 +vn 0.1092 -0.8286 -0.5490 +vn 0.0000 0.3805 -0.9247 +vn 0.1804 0.3805 -0.9070 +vn 0.0000 -0.9217 -0.3879 +vn 0.0757 -0.9217 -0.3804 +vn 0.0000 0.1939 -0.9810 +vn 0.1914 0.1939 -0.9622 +vn 0.0000 -0.9796 -0.2010 +vn 0.0392 -0.9796 -0.1971 +vn 0.0000 0.0000 -1.0000 +vn 0.1951 0.0000 -0.9808 +vn 0.0000 0.9796 -0.2010 +vn 0.0000 1.0000 0.0000 +vn 0.0392 0.9796 -0.1971 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 -0.1939 -0.9810 +vn 0.1914 -0.1939 -0.9622 +vn 0.0000 0.9217 -0.3879 +vn 0.0757 0.9217 -0.3804 +vn 0.3754 -0.1939 -0.9063 +vn 0.3539 -0.3805 -0.8544 +vn 0.1484 0.9217 -0.3583 +vn 0.2142 0.8286 -0.5171 +vn 0.3189 -0.5528 -0.7699 +vn 0.2717 0.7040 -0.6561 +vn 0.2717 -0.7040 -0.6561 +vn 0.3189 0.5528 -0.7699 +vn 0.2142 -0.8286 -0.5171 +vn 0.3539 0.3805 -0.8544 +vn 0.1484 -0.9217 -0.3583 +vn 0.3754 0.1939 -0.9063 +vn 0.0769 -0.9796 -0.1856 +vn 0.3827 0.0000 -0.9239 +vn 0.0769 0.9796 -0.1856 +vn 0.3110 -0.8286 -0.4654 +vn 0.2155 -0.9217 -0.3225 +vn 0.5137 0.3805 -0.7689 +vn 0.5450 0.1939 -0.8157 +vn 0.1116 -0.9796 -0.1671 +vn 0.5556 0.0000 -0.8314 +vn 0.1116 0.9796 -0.1671 +vn 0.5450 -0.1939 -0.8157 +vn 0.2155 0.9217 -0.3225 +vn 0.5137 -0.3805 -0.7689 +vn 0.3110 0.8286 -0.4654 +vn 0.4630 -0.5528 -0.6929 +vn 0.3945 0.7040 -0.5904 +vn 0.3945 -0.7040 -0.5904 +vn 0.4630 0.5528 -0.6929 +vn 0.2743 0.9217 -0.2743 +vn 0.3958 0.8286 -0.3958 +vn 0.6539 -0.3805 -0.6539 +vn 0.5893 -0.5528 -0.5893 +vn 0.5021 0.7040 -0.5021 +vn 0.5021 -0.7040 -0.5021 +vn 0.5893 0.5528 -0.5893 +vn 0.3958 -0.8286 -0.3958 +vn 0.6539 0.3805 -0.6539 +vn 0.2743 -0.9217 -0.2743 +vn 0.6937 0.1939 -0.6937 +vn 0.1421 -0.9796 -0.1421 +vn 0.7071 0.0000 -0.7071 +vn 0.1421 0.9796 -0.1421 +vn 0.6937 -0.1939 -0.6937 +vn 0.7689 0.3805 -0.5137 +vn 0.8157 0.1939 -0.5450 +vn 0.3225 -0.9217 -0.2155 +vn 0.1671 -0.9796 -0.1116 +vn 0.8314 0.0000 -0.5556 +vn 0.1671 0.9796 -0.1116 +vn 0.8157 -0.1939 -0.5450 +vn 0.3225 0.9217 -0.2155 +vn 0.7689 -0.3805 -0.5137 +vn 0.4654 0.8286 -0.3110 +vn 0.6929 -0.5528 -0.4630 +vn 0.5904 0.7040 -0.3945 +vn 0.5904 -0.7040 -0.3945 +vn 0.6929 0.5528 -0.4630 +vn 0.4654 -0.8286 -0.3110 +vn 0.8544 -0.3805 -0.3539 +vn 0.7699 -0.5528 -0.3189 +vn 0.5171 0.8286 -0.2142 +vn 0.6561 0.7040 -0.2717 +vn 0.6561 -0.7040 -0.2717 +vn 0.7699 0.5528 -0.3189 +vn 0.5171 -0.8286 -0.2142 +vn 0.8544 0.3805 -0.3539 +vn 0.3583 -0.9217 -0.1484 +vn 0.9063 0.1939 -0.3754 +vn 0.1856 -0.9796 -0.0769 +vn 0.9239 0.0000 -0.3827 +vn 0.1856 0.9796 -0.0769 +vn 0.9063 -0.1939 -0.3754 +vn 0.3583 0.9217 -0.1484 +vn 0.3804 -0.9217 -0.0757 +vn 0.1971 -0.9796 -0.0392 +vn 0.9622 0.1939 -0.1914 +vn 0.9808 0.0000 -0.1951 +vn 0.1971 0.9796 -0.0392 +vn 0.9622 -0.1939 -0.1914 +vn 0.3804 0.9217 -0.0757 +vn 0.9070 -0.3805 -0.1804 +vn 0.5490 0.8286 -0.1092 +vn 0.8173 -0.5528 -0.1626 +vn 0.6965 0.7040 -0.1385 +vn 0.6965 -0.7040 -0.1385 +vn 0.8173 0.5528 -0.1626 +vn 0.5490 -0.8286 -0.1092 +vn 0.9070 0.3805 -0.1804 +vn 0.5598 0.8286 0.0000 +vn 0.7101 0.7040 0.0000 +vn 0.8333 -0.5528 0.0000 +vn 0.7101 -0.7040 0.0000 +vn 0.8333 0.5528 0.0000 +vn 0.5598 -0.8286 0.0000 +vn 0.9247 0.3805 0.0000 +vn 0.3879 -0.9217 0.0000 +vn 0.9810 0.1939 0.0000 +vn 0.2010 -0.9796 0.0000 +vn 1.0000 0.0000 0.0000 +vn 0.2010 0.9796 0.0000 +vn 0.9810 -0.1939 0.0000 +vn 0.3879 0.9217 0.0000 +vn 0.9247 -0.3805 0.0000 +vn 0.9622 0.1939 0.1914 +vn 0.9808 0.0000 0.1951 +vn 0.1971 0.9796 0.0392 +vn 0.1971 -0.9796 0.0392 +vn 0.9622 -0.1939 0.1914 +vn 0.3804 0.9217 0.0757 +vn 0.9070 -0.3805 0.1804 +vn 0.5490 0.8286 0.1092 +vn 0.8173 -0.5528 0.1626 +vn 0.6965 0.7040 0.1385 +vn 0.6965 -0.7040 0.1385 +vn 0.8173 0.5528 0.1626 +vn 0.5490 -0.8286 0.1092 +vn 0.9070 0.3805 0.1804 +vn 0.3804 -0.9217 0.0757 +vn 0.7699 -0.5528 0.3189 +vn 0.6561 -0.7040 0.2717 +vn 0.6561 0.7040 0.2717 +vn 0.7699 0.5528 0.3189 +vn 0.5171 -0.8286 0.2142 +vn 0.8544 0.3805 0.3539 +vn 0.3583 -0.9217 0.1484 +vn 0.9063 0.1939 0.3754 +vn 0.1856 -0.9796 0.0769 +vn 0.9239 0.0000 0.3827 +vn 0.1856 0.9796 0.0769 +vn 0.9063 -0.1939 0.3754 +vn 0.3583 0.9217 0.1484 +vn 0.8544 -0.3805 0.3539 +vn 0.5171 0.8286 0.2142 +vn 0.1671 -0.9796 0.1116 +vn 0.8314 0.0000 0.5556 +vn 0.8157 -0.1939 0.5450 +vn 0.1671 0.9796 0.1116 +vn 0.3225 0.9217 0.2155 +vn 0.7689 -0.3805 0.5137 +vn 0.4654 0.8286 0.3110 +vn 0.6929 -0.5528 0.4630 +vn 0.5904 0.7040 0.3945 +vn 0.5904 -0.7040 0.3945 +vn 0.6929 0.5528 0.4630 +vn 0.4654 -0.8286 0.3110 +vn 0.7689 0.3805 0.5137 +vn 0.3225 -0.9217 0.2155 +vn 0.8157 0.1939 0.5450 +vn 0.5021 -0.7040 0.5021 +vn 0.3958 -0.8286 0.3958 +vn 0.5893 0.5528 0.5893 +vn 0.6539 0.3805 0.6539 +vn 0.2743 -0.9217 0.2743 +vn 0.6937 0.1939 0.6937 +vn 0.1421 -0.9796 0.1421 +vn 0.7071 0.0000 0.7071 +vn 0.1421 0.9796 0.1421 +vn 0.6937 -0.1939 0.6937 +vn 0.2743 0.9217 0.2743 +vn 0.6539 -0.3805 0.6539 +vn 0.3958 0.8286 0.3958 +vn 0.5893 -0.5528 0.5893 +vn 0.5021 0.7040 0.5021 +vn 0.1116 0.9796 0.1671 +vn 0.2155 0.9217 0.3225 +vn 0.5450 -0.1939 0.8157 +vn 0.5137 -0.3805 0.7689 +vn 0.3110 0.8286 0.4654 +vn 0.4630 -0.5528 0.6929 +vn 0.3945 0.7040 0.5904 +vn 0.3945 -0.7040 0.5904 +vn 0.4630 0.5528 0.6929 +vn 0.3110 -0.8286 0.4654 +vn 0.5137 0.3805 0.7689 +vn 0.2155 -0.9217 0.3225 +vn 0.5450 0.1939 0.8157 +vn 0.1116 -0.9796 0.1671 +vn 0.5556 0.0000 0.8314 +vn 0.3189 0.5528 0.7699 +vn 0.3539 0.3805 0.8544 +vn 0.2142 -0.8286 0.5171 +vn 0.1484 -0.9217 0.3583 +vn 0.3754 0.1939 0.9063 +vn 0.0769 -0.9796 0.1856 +vn 0.3827 0.0000 0.9239 +vn 0.0769 0.9796 0.1856 +vn 0.3754 -0.1939 0.9063 +vn 0.1484 0.9217 0.3583 +vn 0.3539 -0.3805 0.8544 +vn 0.2142 0.8286 0.5171 +vn 0.3189 -0.5528 0.7699 +vn 0.2717 0.7040 0.6561 +vn 0.2717 -0.7040 0.6561 +vn 0.1914 -0.1939 0.9622 +vn 0.1804 -0.3805 0.9070 +vn 0.0757 0.9217 0.3804 +vn 0.1092 0.8286 0.5490 +vn 0.1626 -0.5528 0.8173 +vn 0.1385 0.7040 0.6965 +vn 0.1385 -0.7040 0.6965 +vn 0.1626 0.5528 0.8173 +vn 0.1092 -0.8286 0.5490 +vn 0.1804 0.3805 0.9070 +vn 0.0757 -0.9217 0.3804 +vn 0.1914 0.1939 0.9622 +vn 0.0392 -0.9796 0.1971 +vn 0.1951 0.0000 0.9808 +vn 0.0392 0.9796 0.1971 +vn 0.0000 -0.8286 0.5598 +vn 0.0000 -0.9217 0.3879 +vn 0.0000 0.3805 0.9247 +vn 0.0000 0.1939 0.9810 +vn 0.0000 -0.9796 0.2010 +vn 0.0000 0.0000 1.0000 +vn 0.0000 0.9796 0.2010 +vn 0.0000 -0.1939 0.9810 +vn 0.0000 0.9217 0.3879 +vn 0.0000 -0.3805 0.9247 +vn 0.0000 0.8286 0.5598 +vn 0.0000 -0.5528 0.8333 +vn 0.0000 0.7040 0.7101 +vn 0.0000 -0.7040 0.7101 +vn 0.0000 0.5528 0.8333 +vn -0.0757 0.9217 0.3804 +vn -0.1092 0.8286 0.5490 +vn -0.1804 -0.3805 0.9070 +vn -0.1626 -0.5528 0.8173 +vn -0.1385 0.7040 0.6965 +vn -0.1385 -0.7040 0.6965 +vn -0.1626 0.5528 0.8173 +vn -0.1092 -0.8286 0.5490 +vn -0.1804 0.3805 0.9070 +vn -0.0757 -0.9217 0.3804 +vn -0.1914 0.1939 0.9622 +vn -0.0392 -0.9796 0.1971 +vn -0.1951 0.0000 0.9808 +vn -0.0392 0.9796 0.1971 +vn -0.1914 -0.1939 0.9622 +vn -0.3539 0.3805 0.8544 +vn -0.3754 0.1939 0.9063 +vn -0.1484 -0.9217 0.3583 +vn -0.0769 -0.9796 0.1856 +vn -0.3827 0.0000 0.9239 +vn -0.0769 0.9796 0.1856 +vn -0.3754 -0.1939 0.9063 +vn -0.1484 0.9217 0.3583 +vn -0.3539 -0.3805 0.8544 +vn -0.2142 0.8286 0.5171 +vn -0.3189 -0.5528 0.7699 +vn -0.2717 0.7040 0.6561 +vn -0.2717 -0.7040 0.6561 +vn -0.3189 0.5528 0.7699 +vn -0.2142 -0.8286 0.5171 +vn -0.5137 -0.3805 0.7689 +vn -0.4630 -0.5528 0.6929 +vn -0.3110 0.8286 0.4654 +vn -0.3945 0.7040 0.5904 +vn -0.3945 -0.7040 0.5904 +vn -0.4630 0.5528 0.6929 +vn -0.3110 -0.8286 0.4654 +vn -0.5137 0.3805 0.7689 +vn -0.2155 -0.9217 0.3225 +vn -0.5450 0.1939 0.8157 +vn -0.1116 -0.9796 0.1671 +vn -0.5556 0.0000 0.8314 +vn -0.1116 0.9796 0.1671 +vn -0.5450 -0.1939 0.8157 +vn -0.2155 0.9217 0.3225 +vn -0.2743 -0.9217 0.2743 +vn -0.1421 -0.9796 0.1421 +vn -0.6937 0.1939 0.6937 +vn -0.7071 0.0000 0.7071 +vn -0.1421 0.9796 0.1421 +vn -0.6937 -0.1939 0.6937 +vn -0.2743 0.9217 0.2743 +vn -0.6539 -0.3805 0.6539 +vn -0.3958 0.8286 0.3958 +vn -0.5893 -0.5528 0.5893 +vn -0.5021 0.7040 0.5021 +vn -0.5021 -0.7040 0.5021 +vn -0.5893 0.5528 0.5893 +vn -0.3958 -0.8286 0.3958 +vn -0.6539 0.3805 0.6539 +vn -0.6929 -0.5528 0.4630 +vn -0.5904 -0.7040 0.3945 +vn -0.5904 0.7040 0.3945 +vn -0.6929 0.5528 0.4630 +vn -0.4654 -0.8286 0.3110 +vn -0.7689 0.3805 0.5137 +vn -0.3225 -0.9217 0.2155 +vn -0.8157 0.1939 0.5450 +vn -0.1671 -0.9796 0.1116 +vn -0.8314 0.0000 0.5556 +vn -0.1671 0.9796 0.1116 +vn -0.8157 -0.1939 0.5450 +vn -0.3225 0.9217 0.2155 +vn -0.7689 -0.3805 0.5137 +vn -0.4654 0.8286 0.3110 +vn -0.1856 0.9796 0.0769 +vn -0.1856 -0.9796 0.0769 +vn -0.9239 0.0000 0.3827 +vn -0.9063 -0.1939 0.3754 +vn -0.3583 0.9217 0.1484 +vn -0.8544 -0.3805 0.3539 +vn -0.5171 0.8286 0.2142 +vn -0.7699 -0.5528 0.3189 +vn -0.6561 0.7040 0.2717 +vn -0.6561 -0.7040 0.2717 +vn -0.7699 0.5528 0.3189 +vn -0.5171 -0.8286 0.2142 +vn -0.8544 0.3805 0.3539 +vn -0.3583 -0.9217 0.1484 +vn -0.9063 0.1939 0.3754 +vn -0.6965 0.7040 0.1385 +vn -0.8173 0.5528 0.1626 +vn -0.6965 -0.7040 0.1385 +vn -0.5490 -0.8286 0.1092 +vn -0.9070 0.3805 0.1804 +vn -0.3804 -0.9217 0.0757 +vn -0.9622 0.1939 0.1914 +vn -0.1971 -0.9796 0.0392 +vn -0.9808 0.0000 0.1951 +vn -0.1971 0.9796 0.0392 +vn -0.9622 -0.1939 0.1914 +vn -0.3804 0.9217 0.0757 +vn -0.9070 -0.3805 0.1804 +vn -0.5490 0.8286 0.1092 +vn -0.8173 -0.5528 0.1626 +vn -1.0000 0.0000 0.0000 +vn -0.9810 -0.1939 0.0000 +vn -0.2010 0.9796 0.0000 +vn -0.3879 0.9217 0.0000 +vn -0.9247 -0.3805 0.0000 +vn -0.5598 0.8286 0.0000 +vn -0.8333 -0.5528 0.0000 +vn -0.7101 0.7040 0.0000 +vn -0.7101 -0.7040 0.0000 +vn -0.8333 0.5528 0.0000 +vn -0.5598 -0.8286 0.0000 +vn -0.9247 0.3805 0.0000 +vn -0.3879 -0.9217 0.0000 +vn -0.9810 0.1939 0.0000 +vn -0.2010 -0.9796 0.0000 +vn -0.6965 -0.7040 -0.1385 +vn -0.5490 -0.8286 -0.1092 +vn -0.8173 0.5528 -0.1626 +vn -0.9070 0.3805 -0.1804 +vn -0.3804 -0.9217 -0.0757 +vn -0.9622 0.1939 -0.1914 +vn -0.1971 -0.9796 -0.0392 +vn -0.9808 0.0000 -0.1951 +vn -0.1971 0.9796 -0.0392 +vn -0.9622 -0.1939 -0.1914 +vn -0.3804 0.9217 -0.0757 +vn -0.9070 -0.3805 -0.1804 +vn -0.5490 0.8286 -0.1092 +vn -0.8173 -0.5528 -0.1626 +vn -0.6965 0.7040 -0.1385 +vn -0.1856 0.9796 -0.0769 +vn -0.3583 0.9217 -0.1484 +vn -0.9063 -0.1939 -0.3754 +vn -0.8544 -0.3805 -0.3539 +vn -0.5171 0.8286 -0.2142 +vn -0.7699 -0.5528 -0.3189 +vn -0.6561 0.7040 -0.2717 +vn -0.6561 -0.7040 -0.2717 +vn -0.7699 0.5528 -0.3189 +vn -0.5171 -0.8286 -0.2142 +vn -0.8544 0.3805 -0.3539 +vn -0.3583 -0.9217 -0.1484 +vn -0.9063 0.1939 -0.3754 +vn -0.1856 -0.9796 -0.0769 +vn -0.9239 0.0000 -0.3827 +vn -0.6929 0.5528 -0.4630 +vn -0.7689 0.3805 -0.5137 +vn -0.4654 -0.8286 -0.3110 +vn -0.3225 -0.9217 -0.2155 +vn -0.8157 0.1939 -0.5450 +vn -0.1671 -0.9796 -0.1116 +vn -0.8314 0.0000 -0.5556 +vn -0.1671 0.9796 -0.1116 +vn -0.8157 -0.1939 -0.5450 +vn -0.3225 0.9217 -0.2155 +vn -0.7689 -0.3805 -0.5137 +vn -0.4654 0.8286 -0.3110 +vn -0.6929 -0.5528 -0.4630 +vn -0.5904 0.7040 -0.3945 +vn -0.5904 -0.7040 -0.3945 +vn -0.6937 -0.1939 -0.6937 +vn -0.6539 -0.3805 -0.6539 +vn -0.2743 0.9217 -0.2743 +vn -0.3958 0.8286 -0.3958 +vn -0.5893 -0.5528 -0.5893 +vn -0.5021 0.7040 -0.5021 +vn -0.5021 -0.7040 -0.5021 +vn -0.5893 0.5528 -0.5893 +vn -0.3958 -0.8286 -0.3958 +vn -0.6539 0.3805 -0.6539 +vn -0.2743 -0.9217 -0.2743 +vn -0.6937 0.1939 -0.6937 +vn -0.1421 -0.9796 -0.1421 +vn -0.7071 0.0000 -0.7071 +vn -0.1421 0.9796 -0.1421 +vn -0.3110 -0.8286 -0.4654 +vn -0.2155 -0.9217 -0.3225 +vn -0.5137 0.3805 -0.7689 +vn -0.5450 0.1939 -0.8157 +vn -0.1116 -0.9796 -0.1671 +vn -0.5556 0.0000 -0.8314 +vn -0.1116 0.9796 -0.1671 +vn -0.5450 -0.1939 -0.8157 +vn -0.2155 0.9217 -0.3225 +vn -0.5137 -0.3805 -0.7689 +vn -0.3110 0.8286 -0.4654 +vn -0.4630 -0.5528 -0.6929 +vn -0.3945 0.7040 -0.5904 +vn -0.3945 -0.7040 -0.5904 +vn -0.4630 0.5528 -0.6929 +vn -0.3539 -0.3805 -0.8544 +vn -0.3189 -0.5528 -0.7699 +vn -0.2142 0.8286 -0.5171 +vn -0.2717 0.7040 -0.6561 +vn -0.2717 -0.7040 -0.6561 +vn -0.3189 0.5528 -0.7699 +vn -0.2142 -0.8286 -0.5171 +vn -0.3539 0.3805 -0.8544 +vn -0.1484 -0.9217 -0.3583 +vn -0.3754 0.1939 -0.9063 +vn -0.0769 -0.9796 -0.1856 +vn -0.3827 0.0000 -0.9239 +vn -0.0769 0.9796 -0.1856 +vn -0.3754 -0.1939 -0.9063 +vn -0.1484 0.9217 -0.3583 +vn -0.0757 -0.9217 -0.3804 +vn -0.0392 -0.9796 -0.1971 +vn -0.1914 0.1939 -0.9622 +vn -0.1951 0.0000 -0.9808 +vn -0.0392 0.9796 -0.1971 +vn -0.1914 -0.1939 -0.9622 +vn -0.0757 0.9217 -0.3804 +vn -0.1804 -0.3805 -0.9070 +vn -0.1092 0.8286 -0.5490 +vn -0.1626 -0.5528 -0.8173 +vn -0.1385 0.7040 -0.6965 +vn -0.1385 -0.7040 -0.6965 +vn -0.1626 0.5528 -0.8173 +vn -0.1092 -0.8286 -0.5490 +vn -0.1804 0.3805 -0.9070 +usemtl __tb_info_player_start +s 1 +f 479/1/1 478/2/2 20/3/3 21/4/4 +f 4/5/5 3/6/6 13/7/7 14/8/8 +f 480/9/9 479/1/1 21/4/4 22/10/10 +f 5/11/11 4/5/5 14/8/8 15/12/12 +f 10/13/13 480/9/9 22/10/10 23/14/14 +f 6/15/15 5/11/11 15/12/12 16/16/16 +f 481/17/17 10/13/13 23/14/14 24/18/18 +f 7/19/19 6/15/15 16/16/16 17/20/20 +f 482/21/21 481/17/17 24/18/18 25/22/22 +f 8/23/23 7/19/19 17/20/20 18/24/24 +f 1/25/25 297/26/26 11/27/27 +f 206/28/28 482/21/21 25/22/22 +f 9/29/29 8/30/23 18/31/24 19/32/30 +f 2/33/31 1/25/25 11/27/27 12/34/32 +f 478/2/2 9/29/29 19/32/30 20/3/3 +f 3/6/6 2/33/31 12/34/32 13/7/7 +f 20/3/3 19/32/30 34/35/33 35/36/34 +f 13/7/7 12/34/32 27/37/35 28/38/36 +f 21/4/4 20/3/3 35/36/34 36/39/37 +f 14/8/8 13/7/7 28/38/36 29/40/38 +f 22/10/10 21/4/4 36/39/37 37/41/39 +f 15/12/12 14/8/8 29/40/38 30/42/40 +f 23/14/14 22/10/10 37/41/39 38/43/41 +f 16/16/16 15/12/12 30/42/40 31/44/42 +f 24/18/18 23/14/14 38/43/41 39/45/43 +f 17/20/20 16/16/16 31/44/42 32/46/44 +f 25/22/22 24/18/18 39/45/43 40/47/45 +f 18/24/24 17/20/20 32/46/44 33/48/46 +f 11/27/27 297/26/26 26/49/47 +f 206/28/28 25/22/22 40/47/45 +f 19/32/30 18/31/24 33/50/46 34/35/33 +f 12/34/32 11/27/27 26/49/47 27/37/35 +f 39/45/43 38/43/41 53/51/48 54/52/49 +f 32/46/44 31/44/42 46/53/50 47/54/51 +f 40/47/45 39/45/43 54/52/49 55/55/52 +f 33/48/46 32/46/44 47/54/51 48/56/53 +f 26/49/47 297/26/26 41/57/54 +f 206/28/28 40/47/45 55/55/52 +f 34/35/33 33/50/46 48/58/53 49/59/55 +f 27/37/35 26/49/47 41/57/54 42/60/56 +f 35/36/34 34/35/33 49/59/55 50/61/57 +f 28/38/36 27/37/35 42/60/56 43/62/58 +f 36/39/37 35/36/34 50/61/57 51/63/59 +f 29/40/38 28/38/36 43/62/58 44/64/60 +f 37/41/39 36/39/37 51/63/59 52/65/61 +f 30/42/40 29/40/38 44/64/60 45/66/62 +f 38/43/41 37/41/39 52/65/61 53/51/48 +f 31/44/42 30/42/40 45/66/62 46/53/50 +f 43/62/58 42/60/56 57/67/63 58/68/64 +f 51/63/59 50/61/57 65/69/65 66/70/66 +f 44/64/60 43/62/58 58/68/64 59/71/67 +f 52/65/61 51/63/59 66/70/66 67/72/68 +f 45/66/62 44/64/60 59/71/67 60/73/69 +f 53/51/48 52/65/61 67/72/68 68/74/70 +f 46/53/50 45/66/62 60/73/69 61/75/71 +f 54/52/49 53/51/48 68/74/70 69/76/72 +f 47/54/51 46/53/50 61/75/71 62/77/73 +f 55/55/52 54/52/49 69/76/72 70/78/74 +f 48/56/53 47/54/51 62/77/73 63/79/75 +f 41/57/54 297/26/26 56/80/76 +f 206/28/28 55/55/52 70/78/74 +f 49/59/55 48/58/53 63/81/75 64/82/77 +f 42/60/56 41/57/54 56/80/76 57/67/63 +f 50/61/57 49/59/55 64/82/77 65/69/65 +f 62/77/73 61/75/71 76/83/78 77/84/79 +f 70/78/74 69/76/72 84/85/80 85/86/81 +f 63/79/75 62/77/73 77/84/79 78/87/82 +f 56/80/76 297/26/26 71/88/83 +f 206/28/28 70/78/74 85/86/81 +f 64/82/77 63/81/75 78/89/82 79/90/84 +f 57/67/63 56/80/76 71/88/83 72/91/85 +f 65/69/65 64/82/77 79/90/84 80/92/86 +f 58/68/64 57/67/63 72/91/85 73/93/87 +f 66/70/66 65/69/65 80/92/86 81/94/88 +f 59/71/67 58/68/64 73/93/87 74/95/89 +f 67/72/68 66/70/66 81/94/88 82/96/90 +f 60/73/69 59/71/67 74/95/89 75/97/91 +f 68/74/70 67/72/68 82/96/90 83/98/92 +f 61/75/71 60/73/69 75/97/91 76/83/78 +f 69/76/72 68/74/70 83/98/92 84/85/80 +f 81/94/88 80/92/86 95/99/93 96/100/94 +f 74/95/89 73/93/87 88/101/95 89/102/96 +f 82/96/90 81/94/88 96/100/94 97/103/97 +f 75/97/91 74/95/89 89/102/96 90/104/98 +f 83/98/92 82/96/90 97/103/97 98/105/99 +f 76/83/78 75/97/91 90/104/98 91/106/100 +f 84/85/80 83/98/92 98/105/99 99/107/101 +f 77/84/79 76/83/78 91/106/100 92/108/102 +f 85/86/81 84/85/80 99/107/101 100/109/103 +f 78/87/82 77/84/79 92/108/102 93/110/104 +f 71/88/83 297/26/26 86/111/105 +f 206/28/28 85/86/81 100/109/103 +f 79/90/84 78/89/82 93/112/104 94/113/106 +f 72/91/85 71/88/83 86/111/105 87/114/107 +f 80/92/86 79/90/84 94/113/106 95/99/93 +f 73/93/87 72/91/85 87/114/107 88/101/95 +f 100/109/103 99/107/101 114/115/108 115/116/109 +f 93/110/104 92/108/102 107/117/110 108/118/111 +f 86/111/105 297/26/26 101/119/112 +f 206/28/28 100/109/103 115/116/109 +f 94/113/106 93/112/104 108/120/111 109/121/113 +f 87/114/107 86/111/105 101/119/112 102/122/114 +f 95/99/93 94/113/106 109/121/113 110/123/115 +f 88/101/95 87/114/107 102/122/114 103/124/116 +f 96/100/94 95/99/93 110/123/115 111/125/117 +f 89/102/96 88/101/95 103/124/116 104/126/118 +f 97/103/97 96/100/94 111/125/117 112/127/119 +f 90/104/98 89/102/96 104/126/118 105/128/120 +f 98/105/99 97/103/97 112/127/119 113/129/121 +f 91/106/100 90/104/98 105/128/120 106/130/122 +f 99/107/101 98/105/99 113/129/121 114/115/108 +f 92/108/102 91/106/100 106/130/122 107/117/110 +f 104/126/118 103/124/116 118/131/123 119/132/124 +f 112/127/119 111/125/117 126/133/125 127/134/126 +f 105/128/120 104/126/118 119/132/124 120/135/127 +f 113/129/121 112/127/119 127/134/126 128/136/128 +f 106/130/122 105/128/120 120/135/127 121/137/129 +f 114/115/108 113/129/121 128/136/128 129/138/130 +f 107/117/110 106/130/122 121/137/129 122/139/131 +f 115/116/109 114/115/108 129/138/130 130/140/132 +f 108/118/111 107/117/110 122/139/131 123/141/133 +f 101/119/112 297/26/26 116/142/134 +f 206/28/28 115/116/109 130/140/132 +f 109/121/113 108/120/111 123/143/133 124/144/135 +f 102/122/114 101/119/112 116/142/134 117/145/136 +f 110/123/115 109/121/113 124/144/135 125/146/137 +f 103/124/116 102/122/114 117/145/136 118/131/123 +f 111/125/117 110/123/115 125/146/137 126/133/125 +f 123/147/133 122/148/131 137/149/138 138/150/139 +f 116/151/134 297/152/26 131/153/140 +f 206/154/28 130/155/132 145/156/141 +f 124/157/135 123/158/133 138/159/139 139/160/142 +f 117/161/136 116/151/134 131/153/140 132/162/143 +f 125/163/137 124/157/135 139/160/142 140/164/144 +f 118/165/123 117/161/136 132/162/143 133/166/145 +f 126/167/125 125/163/137 140/164/144 141/168/146 +f 119/169/124 118/165/123 133/166/145 134/170/147 +f 127/171/126 126/167/125 141/168/146 142/172/148 +f 120/173/127 119/169/124 134/170/147 135/174/149 +f 128/175/128 127/171/126 142/172/148 143/176/150 +f 121/177/129 120/173/127 135/174/149 136/178/151 +f 129/179/130 128/175/128 143/176/150 144/180/152 +f 122/148/131 121/177/129 136/178/151 137/149/138 +f 130/155/132 129/179/130 144/180/152 145/156/141 +f 142/172/148 141/168/146 156/181/153 157/182/154 +f 135/174/149 134/170/147 149/183/155 150/184/156 +f 143/176/150 142/172/148 157/182/154 158/185/157 +f 136/178/151 135/174/149 150/184/156 151/186/158 +f 144/180/152 143/176/150 158/185/157 159/187/159 +f 137/149/138 136/178/151 151/186/158 152/188/160 +f 145/156/141 144/180/152 159/187/159 160/189/161 +f 138/150/139 137/149/138 152/188/160 153/190/162 +f 131/153/140 297/152/26 146/191/163 +f 206/154/28 145/156/141 160/189/161 +f 139/160/142 138/159/139 153/192/162 154/193/164 +f 132/162/143 131/153/140 146/191/163 147/194/165 +f 140/164/144 139/160/142 154/193/164 155/195/166 +f 133/166/145 132/162/143 147/194/165 148/196/167 +f 141/168/146 140/164/144 155/195/166 156/181/153 +f 134/170/147 133/166/145 148/196/167 149/183/155 +f 206/154/28 160/189/161 175/197/168 +f 154/193/164 153/192/162 168/198/169 169/199/170 +f 147/194/165 146/191/163 161/200/171 162/201/172 +f 155/195/166 154/193/164 169/199/170 170/202/173 +f 148/196/167 147/194/165 162/201/172 163/203/174 +f 156/181/153 155/195/166 170/202/173 171/204/175 +f 149/183/155 148/196/167 163/203/174 164/205/176 +f 157/182/154 156/181/153 171/204/175 172/206/177 +f 150/184/156 149/183/155 164/205/176 165/207/178 +f 158/185/157 157/182/154 172/206/177 173/208/179 +f 151/186/158 150/184/156 165/207/178 166/209/180 +f 159/187/159 158/185/157 173/208/179 174/210/181 +f 152/188/160 151/186/158 166/209/180 167/211/182 +f 160/189/161 159/187/159 174/210/181 175/197/168 +f 153/190/162 152/188/160 167/211/182 168/212/169 +f 146/191/163 297/152/26 161/200/171 +f 173/208/179 172/206/177 187/213/183 188/214/184 +f 166/209/180 165/207/178 180/215/185 181/216/186 +f 174/210/181 173/208/179 188/214/184 189/217/187 +f 167/211/182 166/209/180 181/216/186 182/218/188 +f 175/197/168 174/210/181 189/217/187 190/219/189 +f 168/212/169 167/211/182 182/218/188 183/220/190 +f 161/200/171 297/152/26 176/221/191 +f 206/154/28 175/197/168 190/219/189 +f 169/199/170 168/198/169 183/222/190 184/223/192 +f 162/201/172 161/200/171 176/221/191 177/224/193 +f 170/202/173 169/199/170 184/223/192 185/225/194 +f 163/203/174 162/201/172 177/224/193 178/226/195 +f 171/204/175 170/202/173 185/225/194 186/227/196 +f 164/205/176 163/203/174 178/226/195 179/228/197 +f 172/206/177 171/204/175 186/227/196 187/213/183 +f 165/207/178 164/205/176 179/228/197 180/215/185 +f 177/224/193 176/221/191 191/229/198 192/230/199 +f 185/225/194 184/223/192 199/231/200 200/232/201 +f 178/226/195 177/224/193 192/230/199 193/233/202 +f 186/227/196 185/225/194 200/232/201 201/234/203 +f 179/228/197 178/226/195 193/233/202 194/235/204 +f 187/213/183 186/227/196 201/234/203 202/236/205 +f 180/215/185 179/228/197 194/235/204 195/237/206 +f 188/214/184 187/213/183 202/236/205 203/238/207 +f 181/216/186 180/215/185 195/237/206 196/239/208 +f 189/217/187 188/214/184 203/238/207 204/240/209 +f 182/218/188 181/216/186 196/239/208 197/241/210 +f 190/219/189 189/217/187 204/240/209 205/242/211 +f 183/220/190 182/218/188 197/241/210 198/243/212 +f 176/221/191 297/152/26 191/229/198 +f 206/154/28 190/219/189 205/242/211 +f 184/223/192 183/222/190 198/244/212 199/231/200 +f 196/239/208 195/237/206 211/245/213 212/246/214 +f 204/240/209 203/238/207 219/247/215 220/248/216 +f 197/241/210 196/239/208 212/246/214 213/249/217 +f 205/242/211 204/240/209 220/248/216 221/250/218 +f 198/243/212 197/241/210 213/249/217 214/251/219 +f 191/229/198 297/152/26 207/252/220 +f 206/154/28 205/242/211 221/250/218 +f 199/231/200 198/244/212 214/253/219 215/254/221 +f 192/230/199 191/229/198 207/252/220 208/255/222 +f 200/232/201 199/231/200 215/254/221 216/256/223 +f 193/233/202 192/230/199 208/255/222 209/257/224 +f 201/234/203 200/232/201 216/256/223 217/258/225 +f 194/235/204 193/233/202 209/257/224 210/259/226 +f 202/236/205 201/234/203 217/258/225 218/260/227 +f 195/237/206 194/235/204 210/259/226 211/245/213 +f 203/238/207 202/236/205 218/260/227 219/247/215 +f 216/256/223 215/254/221 230/261/228 231/262/229 +f 209/257/224 208/255/222 223/263/230 224/264/231 +f 217/258/225 216/256/223 231/262/229 232/265/232 +f 210/259/226 209/257/224 224/264/231 225/266/233 +f 218/260/227 217/258/225 232/265/232 233/267/234 +f 211/245/213 210/259/226 225/266/233 226/268/235 +f 219/247/215 218/260/227 233/267/234 234/269/236 +f 212/246/214 211/245/213 226/268/235 227/270/237 +f 220/248/216 219/247/215 234/269/236 235/271/238 +f 213/249/217 212/246/214 227/270/237 228/272/239 +f 221/250/218 220/248/216 235/271/238 236/273/240 +f 214/251/219 213/249/217 228/272/239 229/274/241 +f 207/252/220 297/152/26 222/275/242 +f 206/154/28 221/250/218 236/273/240 +f 215/254/221 214/253/219 229/276/241 230/261/228 +f 208/255/222 207/252/220 222/275/242 223/263/230 +f 235/271/238 234/269/236 249/277/243 250/278/244 +f 228/272/239 227/270/237 242/279/245 243/280/246 +f 236/273/240 235/271/238 250/278/244 251/281/247 +f 229/274/241 228/272/239 243/280/246 244/282/248 +f 222/275/242 297/152/26 237/283/249 +f 206/154/28 236/273/240 251/281/247 +f 230/261/228 229/276/241 244/284/248 245/285/250 +f 223/263/230 222/275/242 237/283/249 238/286/251 +f 231/262/229 230/261/228 245/285/250 246/287/252 +f 224/264/231 223/263/230 238/286/251 239/288/253 +f 232/265/232 231/262/229 246/287/252 247/289/254 +f 225/266/233 224/264/231 239/288/253 240/290/255 +f 233/267/234 232/265/232 247/289/254 248/291/256 +f 226/268/235 225/266/233 240/290/255 241/292/257 +f 234/269/236 233/267/234 248/291/256 249/277/243 +f 227/270/237 226/268/235 241/292/257 242/279/245 +f 239/293/253 238/294/251 253/295/258 254/296/259 +f 247/297/254 246/298/252 261/299/260 262/300/261 +f 240/301/255 239/293/253 254/296/259 255/302/262 +f 248/303/256 247/297/254 262/300/261 263/304/263 +f 241/305/257 240/301/255 255/302/262 256/306/264 +f 249/307/243 248/303/256 263/304/263 264/308/265 +f 242/309/245 241/305/257 256/306/264 257/310/266 +f 250/311/244 249/307/243 264/308/265 265/312/267 +f 243/313/246 242/309/245 257/310/266 258/314/268 +f 251/315/247 250/311/244 265/312/267 266/316/269 +f 244/317/248 243/313/246 258/314/268 259/318/270 +f 237/319/249 297/320/26 252/321/271 +f 206/322/28 251/315/247 266/316/269 +f 245/323/250 244/324/248 259/325/270 260/326/272 +f 238/294/251 237/319/249 252/321/271 253/295/258 +f 246/298/252 245/323/250 260/326/272 261/299/260 +f 258/314/268 257/310/266 272/327/273 273/328/274 +f 266/316/269 265/312/267 280/329/275 281/330/276 +f 259/318/270 258/314/268 273/328/274 274/331/277 +f 252/321/271 297/320/26 267/332/278 +f 206/322/28 266/316/269 281/330/276 +f 260/326/272 259/325/270 274/333/277 275/334/279 +f 253/295/258 252/321/271 267/332/278 268/335/280 +f 261/299/260 260/326/272 275/334/279 276/336/281 +f 254/296/259 253/295/258 268/335/280 269/337/282 +f 262/300/261 261/299/260 276/336/281 277/338/283 +f 255/302/262 254/296/259 269/337/282 270/339/284 +f 263/304/263 262/300/261 277/338/283 278/340/285 +f 256/306/264 255/302/262 270/339/284 271/341/286 +f 264/308/265 263/304/263 278/340/285 279/342/287 +f 257/310/266 256/306/264 271/341/286 272/327/273 +f 265/312/267 264/308/265 279/342/287 280/329/275 +f 277/338/283 276/336/281 291/343/288 292/344/289 +f 270/339/284 269/337/282 284/345/290 285/346/291 +f 278/340/285 277/338/283 292/344/289 293/347/292 +f 271/341/286 270/339/284 285/346/291 286/348/293 +f 279/342/287 278/340/285 293/347/292 294/349/294 +f 272/327/273 271/341/286 286/348/293 287/350/295 +f 280/329/275 279/342/287 294/349/294 295/351/296 +f 273/328/274 272/327/273 287/350/295 288/352/297 +f 281/330/276 280/329/275 295/351/296 296/353/298 +f 274/331/277 273/328/274 288/352/297 289/354/299 +f 267/332/278 297/320/26 282/355/300 +f 206/322/28 281/330/276 296/353/298 +f 275/334/279 274/333/277 289/356/299 290/357/301 +f 268/335/280 267/332/278 282/355/300 283/358/302 +f 276/336/281 275/334/279 290/357/301 291/343/288 +f 269/337/282 268/335/280 283/358/302 284/345/290 +f 296/353/298 295/351/296 311/359/303 312/360/304 +f 289/354/299 288/352/297 304/361/305 305/362/306 +f 282/355/300 297/320/26 298/363/307 +f 206/322/28 296/353/298 312/360/304 +f 290/357/301 289/356/299 305/364/306 306/365/308 +f 283/358/302 282/355/300 298/363/307 299/366/309 +f 291/343/288 290/357/301 306/365/308 307/367/310 +f 284/345/290 283/358/302 299/366/309 300/368/311 +f 292/344/289 291/343/288 307/367/310 308/369/312 +f 285/346/291 284/345/290 300/368/311 301/370/313 +f 293/347/292 292/344/289 308/369/312 309/371/314 +f 286/348/293 285/346/291 301/370/313 302/372/315 +f 294/349/294 293/347/292 309/371/314 310/373/316 +f 287/350/295 286/348/293 302/372/315 303/374/317 +f 295/351/296 294/349/294 310/373/316 311/359/303 +f 288/352/297 287/350/295 303/374/317 304/361/305 +f 309/371/314 308/369/312 323/375/318 324/376/319 +f 302/372/315 301/370/313 316/377/320 317/378/321 +f 310/373/316 309/371/314 324/376/319 325/379/322 +f 303/374/317 302/372/315 317/378/321 318/380/323 +f 311/359/303 310/373/316 325/379/322 326/381/324 +f 304/361/305 303/374/317 318/380/323 319/382/325 +f 312/360/304 311/359/303 326/381/324 327/383/326 +f 305/362/306 304/361/305 319/382/325 320/384/327 +f 298/363/307 297/320/26 313/385/328 +f 206/322/28 312/360/304 327/383/326 +f 306/365/308 305/364/306 320/386/327 321/387/329 +f 299/366/309 298/363/307 313/385/328 314/388/330 +f 307/367/310 306/365/308 321/387/329 322/389/331 +f 300/368/311 299/366/309 314/388/330 315/390/332 +f 308/369/312 307/367/310 322/389/331 323/375/318 +f 301/370/313 300/368/311 315/390/332 316/377/320 +f 313/385/328 297/320/26 328/391/333 +f 206/322/28 327/383/326 342/392/334 +f 321/387/329 320/386/327 335/393/335 336/394/336 +f 314/388/330 313/385/328 328/391/333 329/395/337 +f 322/389/331 321/387/329 336/394/336 337/396/338 +f 315/390/332 314/388/330 329/395/337 330/397/339 +f 323/375/318 322/389/331 337/396/338 338/398/340 +f 316/377/320 315/390/332 330/397/339 331/399/341 +f 324/376/319 323/375/318 338/398/340 339/400/342 +f 317/378/321 316/377/320 331/399/341 332/401/343 +f 325/379/322 324/376/319 339/400/342 340/402/344 +f 318/380/323 317/378/321 332/401/343 333/403/345 +f 326/381/324 325/379/322 340/402/344 341/404/346 +f 319/382/325 318/380/323 333/403/345 334/405/347 +f 327/383/326 326/381/324 341/404/346 342/392/334 +f 320/384/327 319/382/325 334/405/347 335/406/335 +f 332/401/343 331/399/341 346/407/348 347/408/349 +f 340/402/344 339/400/342 354/409/350 355/410/351 +f 333/403/345 332/401/343 347/408/349 348/411/352 +f 341/404/346 340/402/344 355/410/351 356/412/353 +f 334/405/347 333/403/345 348/411/352 349/413/354 +f 342/392/334 341/404/346 356/412/353 357/414/355 +f 335/406/335 334/405/347 349/413/354 350/415/356 +f 328/391/333 297/320/26 343/416/357 +f 206/322/28 342/392/334 357/414/355 +f 336/394/336 335/393/335 350/417/356 351/418/358 +f 329/395/337 328/391/333 343/416/357 344/419/359 +f 337/396/338 336/394/336 351/418/358 352/420/360 +f 330/397/339 329/395/337 344/419/359 345/421/361 +f 338/398/340 337/396/338 352/420/360 353/422/362 +f 331/399/341 330/397/339 345/421/361 346/407/348 +f 339/400/342 338/398/340 353/422/362 354/409/350 +f 351/418/358 350/417/356 365/423/363 366/424/364 +f 344/419/359 343/416/357 358/425/365 359/426/366 +f 352/420/360 351/418/358 366/424/364 367/427/367 +f 345/421/361 344/419/359 359/426/366 360/428/368 +f 353/422/362 352/420/360 367/427/367 368/429/369 +f 346/407/348 345/421/361 360/428/368 361/430/370 +f 354/409/350 353/422/362 368/429/369 369/431/371 +f 347/408/349 346/407/348 361/430/370 362/432/372 +f 355/410/351 354/409/350 369/431/371 370/433/373 +f 348/411/352 347/408/349 362/432/372 363/434/374 +f 356/412/353 355/410/351 370/433/373 371/435/375 +f 349/413/354 348/411/352 363/434/374 364/436/376 +f 357/414/355 356/412/353 371/435/375 372/437/377 +f 350/415/356 349/413/354 364/436/376 365/438/363 +f 343/416/357 297/320/26 358/425/365 +f 206/322/28 357/414/355 372/437/377 +f 370/439/373 369/440/371 384/441/378 385/442/379 +f 363/443/374 362/444/372 377/445/380 378/446/381 +f 371/447/375 370/439/373 385/442/379 386/448/382 +f 364/449/376 363/443/374 378/446/381 379/450/383 +f 372/451/377 371/447/375 386/448/382 387/452/384 +f 365/453/363 364/449/376 379/450/383 380/454/385 +f 358/455/365 297/456/26 373/457/386 +f 206/458/28 372/451/377 387/452/384 +f 366/459/364 365/460/363 380/461/385 381/462/387 +f 359/463/366 358/455/365 373/457/386 374/464/388 +f 367/465/367 366/459/364 381/462/387 382/466/389 +f 360/467/368 359/463/366 374/464/388 375/468/390 +f 368/469/369 367/465/367 382/466/389 383/470/391 +f 361/471/370 360/467/368 375/468/390 376/472/392 +f 369/440/371 368/469/369 383/470/391 384/441/378 +f 362/444/372 361/471/370 376/472/392 377/445/380 +f 374/464/388 373/457/386 388/473/393 389/474/394 +f 382/466/389 381/462/387 396/475/395 397/476/396 +f 375/468/390 374/464/388 389/474/394 390/477/397 +f 383/470/391 382/466/389 397/476/396 398/478/398 +f 376/472/392 375/468/390 390/477/397 391/479/399 +f 384/441/378 383/470/391 398/478/398 399/480/400 +f 377/445/380 376/472/392 391/479/399 392/481/401 +f 385/442/379 384/441/378 399/480/400 400/482/402 +f 378/446/381 377/445/380 392/481/401 393/483/403 +f 386/448/382 385/442/379 400/482/402 401/484/404 +f 379/450/383 378/446/381 393/483/403 394/485/405 +f 387/452/384 386/448/382 401/484/404 402/486/406 +f 380/454/385 379/450/383 394/485/405 395/487/407 +f 373/457/386 297/456/26 388/473/393 +f 206/458/28 387/452/384 402/486/406 +f 381/462/387 380/461/385 395/488/407 396/475/395 +f 393/483/403 392/481/401 407/489/408 408/490/409 +f 401/484/404 400/482/402 415/491/410 416/492/411 +f 394/485/405 393/483/403 408/490/409 409/493/412 +f 402/486/406 401/484/404 416/492/411 417/494/413 +f 395/487/407 394/485/405 409/493/412 410/495/414 +f 388/473/393 297/456/26 403/496/415 +f 206/458/28 402/486/406 417/494/413 +f 396/475/395 395/488/407 410/497/414 411/498/416 +f 389/474/394 388/473/393 403/496/415 404/499/417 +f 397/476/396 396/475/395 411/498/416 412/500/418 +f 390/477/397 389/474/394 404/499/417 405/501/419 +f 398/478/398 397/476/396 412/500/418 413/502/420 +f 391/479/399 390/477/397 405/501/419 406/503/421 +f 399/480/400 398/478/398 413/502/420 414/504/422 +f 392/481/401 391/479/399 406/503/421 407/489/408 +f 400/482/402 399/480/400 414/504/422 415/491/410 +f 412/500/418 411/498/416 426/505/423 427/506/424 +f 405/501/419 404/499/417 419/507/425 420/508/426 +f 413/502/420 412/500/418 427/506/424 428/509/427 +f 406/503/421 405/501/419 420/508/426 421/510/428 +f 414/504/422 413/502/420 428/509/427 429/511/429 +f 407/489/408 406/503/421 421/510/428 422/512/430 +f 415/491/410 414/504/422 429/511/429 430/513/431 +f 408/490/409 407/489/408 422/512/430 423/514/432 +f 416/492/411 415/491/410 430/513/431 431/515/433 +f 409/493/412 408/490/409 423/514/432 424/516/434 +f 417/494/413 416/492/411 431/515/433 432/517/435 +f 410/495/414 409/493/412 424/516/434 425/518/436 +f 403/496/415 297/456/26 418/519/437 +f 206/458/28 417/494/413 432/517/435 +f 411/498/416 410/497/414 425/520/436 426/505/423 +f 404/499/417 403/496/415 418/519/437 419/507/425 +f 431/515/433 430/513/431 445/521/438 446/522/439 +f 424/516/434 423/514/432 438/523/440 439/524/441 +f 432/517/435 431/515/433 446/522/439 447/525/442 +f 425/518/436 424/516/434 439/524/441 440/526/443 +f 418/519/437 297/456/26 433/527/444 +f 206/458/28 432/517/435 447/525/442 +f 426/505/423 425/520/436 440/528/443 441/529/445 +f 419/507/425 418/519/437 433/527/444 434/530/446 +f 427/506/424 426/505/423 441/529/445 442/531/447 +f 420/508/426 419/507/425 434/530/446 435/532/448 +f 428/509/427 427/506/424 442/531/447 443/533/449 +f 421/510/428 420/508/426 435/532/448 436/534/450 +f 429/511/429 428/509/427 443/533/449 444/535/451 +f 422/512/430 421/510/428 436/534/450 437/536/452 +f 430/513/431 429/511/429 444/535/451 445/521/438 +f 423/514/432 422/512/430 437/536/452 438/523/440 +f 443/533/449 442/531/447 457/537/453 458/538/454 +f 436/534/450 435/532/448 450/539/455 451/540/456 +f 444/535/451 443/533/449 458/538/454 459/541/457 +f 437/536/452 436/534/450 451/540/456 452/542/458 +f 445/521/438 444/535/451 459/541/457 460/543/459 +f 438/523/440 437/536/452 452/542/458 453/544/460 +f 446/522/439 445/521/438 460/543/459 461/545/461 +f 439/524/441 438/523/440 453/544/460 454/546/462 +f 447/525/442 446/522/439 461/545/461 462/547/463 +f 440/526/443 439/524/441 454/546/462 455/548/464 +f 433/527/444 297/456/26 448/549/465 +f 206/458/28 447/525/442 462/547/463 +f 441/529/445 440/528/443 455/550/464 456/551/466 +f 434/530/446 433/527/444 448/549/465 449/552/467 +f 442/531/447 441/529/445 456/551/466 457/537/453 +f 435/532/448 434/530/446 449/552/467 450/539/455 +f 462/547/463 461/545/461 476/553/468 477/554/469 +f 455/548/464 454/546/462 469/555/470 470/556/471 +f 448/549/465 297/456/26 463/557/472 +f 206/458/28 462/547/463 477/554/469 +f 456/551/466 455/550/464 470/558/471 471/559/473 +f 449/552/467 448/549/465 463/557/472 464/560/474 +f 457/537/453 456/551/466 471/559/473 472/561/475 +f 450/539/455 449/552/467 464/560/474 465/562/476 +f 458/538/454 457/537/453 472/561/475 473/563/477 +f 451/540/456 450/539/455 465/562/476 466/564/478 +f 459/541/457 458/538/454 473/563/477 474/565/479 +f 452/542/458 451/540/456 466/564/478 467/566/480 +f 460/543/459 459/541/457 474/565/479 475/567/481 +f 453/544/460 452/542/458 467/566/480 468/568/482 +f 461/545/461 460/543/459 475/567/481 476/553/468 +f 454/546/462 453/544/460 468/568/482 469/555/470 +f 466/564/478 465/562/476 3/569/6 4/570/5 +f 474/565/479 473/563/477 479/571/1 480/572/9 +f 467/566/480 466/564/478 4/570/5 5/573/11 +f 475/567/481 474/565/479 480/572/9 10/574/13 +f 468/568/482 467/566/480 5/573/11 6/575/15 +f 476/553/468 475/567/481 10/574/13 481/576/17 +f 469/555/470 468/568/482 6/575/15 7/577/19 +f 477/554/469 476/553/468 481/576/17 482/578/21 +f 470/556/471 469/555/470 7/577/19 8/579/23 +f 463/557/472 297/456/26 1/580/25 +f 206/458/28 477/554/469 482/578/21 +f 471/559/473 470/558/471 8/581/23 9/582/29 +f 464/560/474 463/557/472 1/580/25 2/583/31 +f 472/561/475 471/559/473 9/582/29 478/584/2 +f 465/562/476 464/560/474 2/583/31 3/569/6 +f 473/563/477 472/561/475 478/584/2 479/571/1 diff --git a/tools/trenchbroom/games/Neverball/assets/__tb_item_health_small.obj b/tools/trenchbroom/games/Neverball/assets/__tb_item_health_small.obj new file mode 100644 index 0000000..2f98502 --- /dev/null +++ b/tools/trenchbroom/games/Neverball/assets/__tb_item_health_small.obj @@ -0,0 +1,2066 @@ +# Blender v2.79 (sub 0) OBJ File: '__tb_info_player_start.blend' +# www.blender.org +mtllib __tb_item_health_small.mtl +o ShrinkSphere_Sphere +v 0.000000 -0.002402 -0.024386 +v 0.000000 -0.009515 -0.047835 +v 0.000000 -0.021066 -0.069446 +v 0.000000 -0.036612 -0.088388 +v 0.000000 -0.055554 -0.103934 +v 0.000000 -0.077165 -0.115485 +v 0.000000 -0.100614 -0.122598 +v 0.000000 -0.125000 -0.125000 +v 0.000000 -0.149386 -0.122598 +v 0.000000 -0.228934 -0.069446 +v 0.004758 -0.002402 -0.023918 +v 0.009332 -0.009515 -0.046916 +v 0.013548 -0.021066 -0.068112 +v 0.017244 -0.036612 -0.086690 +v 0.020276 -0.055554 -0.101937 +v 0.022530 -0.077165 -0.113266 +v 0.023918 -0.100614 -0.120242 +v 0.024386 -0.125000 -0.122598 +v 0.023918 -0.149386 -0.120242 +v 0.022530 -0.172835 -0.113266 +v 0.020276 -0.194446 -0.101937 +v 0.017244 -0.213388 -0.086690 +v 0.013548 -0.228934 -0.068112 +v 0.009332 -0.240485 -0.046916 +v 0.004758 -0.247598 -0.023918 +v 0.009332 -0.002402 -0.022530 +v 0.018306 -0.009515 -0.044194 +v 0.026576 -0.021066 -0.064160 +v 0.033825 -0.036612 -0.081660 +v 0.039774 -0.055554 -0.096022 +v 0.044194 -0.077165 -0.106694 +v 0.046916 -0.100614 -0.113266 +v 0.047835 -0.125000 -0.115485 +v 0.046916 -0.149386 -0.113266 +v 0.044194 -0.172835 -0.106694 +v 0.039774 -0.194446 -0.096022 +v 0.033825 -0.213388 -0.081660 +v 0.026576 -0.228934 -0.064160 +v 0.018306 -0.240485 -0.044194 +v 0.009332 -0.247598 -0.022530 +v 0.013548 -0.002402 -0.020276 +v 0.026576 -0.009515 -0.039774 +v 0.038582 -0.021066 -0.057742 +v 0.049106 -0.036612 -0.073492 +v 0.057742 -0.055554 -0.086418 +v 0.064160 -0.077165 -0.096022 +v 0.068112 -0.100614 -0.101937 +v 0.069446 -0.125000 -0.103934 +v 0.068112 -0.149386 -0.101937 +v 0.064160 -0.172835 -0.096022 +v 0.057742 -0.194446 -0.086418 +v 0.049106 -0.213388 -0.073492 +v 0.038582 -0.228934 -0.057742 +v 0.026576 -0.240485 -0.039774 +v 0.013548 -0.247598 -0.020276 +v 0.017244 -0.002402 -0.017244 +v 0.033825 -0.009515 -0.033825 +v 0.049106 -0.021066 -0.049106 +v 0.062500 -0.036612 -0.062500 +v 0.073492 -0.055554 -0.073492 +v 0.081660 -0.077165 -0.081660 +v 0.086690 -0.100614 -0.086690 +v 0.088388 -0.125000 -0.088388 +v 0.086690 -0.149386 -0.086690 +v 0.081660 -0.172835 -0.081660 +v 0.073492 -0.194446 -0.073492 +v 0.062500 -0.213388 -0.062500 +v 0.049106 -0.228934 -0.049106 +v 0.033825 -0.240485 -0.033825 +v 0.017244 -0.247598 -0.017244 +v 0.020276 -0.002402 -0.013548 +v 0.039774 -0.009515 -0.026576 +v 0.057742 -0.021066 -0.038582 +v 0.073492 -0.036612 -0.049106 +v 0.086418 -0.055554 -0.057742 +v 0.096022 -0.077165 -0.064160 +v 0.101937 -0.100614 -0.068112 +v 0.103934 -0.125000 -0.069446 +v 0.101937 -0.149386 -0.068112 +v 0.096022 -0.172835 -0.064160 +v 0.086418 -0.194446 -0.057742 +v 0.073492 -0.213388 -0.049106 +v 0.057742 -0.228934 -0.038582 +v 0.039774 -0.240485 -0.026576 +v 0.020276 -0.247598 -0.013548 +v 0.022530 -0.002402 -0.009332 +v 0.044194 -0.009515 -0.018306 +v 0.064160 -0.021066 -0.026576 +v 0.081660 -0.036612 -0.033825 +v 0.096022 -0.055554 -0.039774 +v 0.106694 -0.077165 -0.044194 +v 0.113266 -0.100614 -0.046916 +v 0.115485 -0.125000 -0.047835 +v 0.113266 -0.149386 -0.046916 +v 0.106694 -0.172835 -0.044194 +v 0.096022 -0.194446 -0.039774 +v 0.081660 -0.213388 -0.033825 +v 0.064160 -0.228934 -0.026576 +v 0.044194 -0.240485 -0.018306 +v 0.022530 -0.247598 -0.009332 +v 0.023918 -0.002402 -0.004757 +v 0.046916 -0.009515 -0.009332 +v 0.068112 -0.021066 -0.013548 +v 0.086690 -0.036612 -0.017244 +v 0.101937 -0.055554 -0.020276 +v 0.113266 -0.077165 -0.022530 +v 0.120242 -0.100614 -0.023918 +v 0.122598 -0.125000 -0.024386 +v 0.120242 -0.149386 -0.023918 +v 0.113266 -0.172835 -0.022530 +v 0.101937 -0.194446 -0.020276 +v 0.086690 -0.213388 -0.017244 +v 0.068112 -0.228934 -0.013548 +v 0.046916 -0.240485 -0.009332 +v 0.023918 -0.247598 -0.004757 +v 0.024386 -0.002402 0.000000 +v 0.047835 -0.009515 0.000000 +v 0.069446 -0.021066 0.000000 +v 0.088388 -0.036612 0.000000 +v 0.103934 -0.055554 0.000000 +v 0.115485 -0.077165 0.000000 +v 0.122598 -0.100614 0.000000 +v 0.125000 -0.125000 0.000000 +v 0.122598 -0.149386 0.000000 +v 0.115485 -0.172835 0.000000 +v 0.103934 -0.194446 0.000000 +v 0.088388 -0.213388 0.000000 +v 0.069446 -0.228934 0.000000 +v 0.047835 -0.240485 0.000000 +v 0.024386 -0.247598 0.000000 +v 0.023918 -0.002402 0.004758 +v 0.046916 -0.009515 0.009332 +v 0.068112 -0.021066 0.013548 +v 0.086690 -0.036612 0.017244 +v 0.101937 -0.055554 0.020277 +v 0.113266 -0.077165 0.022530 +v 0.120242 -0.100614 0.023918 +v 0.122598 -0.125000 0.024386 +v 0.120242 -0.149386 0.023918 +v 0.113266 -0.172835 0.022530 +v 0.101937 -0.194446 0.020277 +v 0.086690 -0.213388 0.017244 +v 0.068112 -0.228934 0.013548 +v 0.046916 -0.240485 0.009332 +v 0.023918 -0.247598 0.004758 +v 0.022530 -0.002402 0.009332 +v 0.044194 -0.009515 0.018306 +v 0.064160 -0.021066 0.026576 +v 0.081660 -0.036612 0.033825 +v 0.096022 -0.055554 0.039774 +v 0.106694 -0.077165 0.044194 +v 0.113266 -0.100614 0.046916 +v 0.115485 -0.125000 0.047835 +v 0.113266 -0.149386 0.046916 +v 0.106694 -0.172835 0.044194 +v 0.096022 -0.194446 0.039774 +v 0.081660 -0.213388 0.033825 +v 0.064160 -0.228934 0.026576 +v 0.044194 -0.240485 0.018306 +v 0.022530 -0.247598 0.009332 +v 0.020276 -0.002402 0.013548 +v 0.039774 -0.009515 0.026576 +v 0.057742 -0.021066 0.038582 +v 0.073492 -0.036612 0.049106 +v 0.086418 -0.055554 0.057743 +v 0.096022 -0.077165 0.064160 +v 0.101937 -0.100614 0.068112 +v 0.103934 -0.125000 0.069446 +v 0.101937 -0.149386 0.068112 +v 0.096022 -0.172835 0.064160 +v 0.086418 -0.194446 0.057743 +v 0.073492 -0.213388 0.049106 +v 0.057742 -0.228934 0.038582 +v 0.039774 -0.240485 0.026576 +v 0.020276 -0.247598 0.013548 +v 0.017244 -0.002402 0.017244 +v 0.033825 -0.009515 0.033825 +v 0.049106 -0.021066 0.049106 +v 0.062500 -0.036612 0.062500 +v 0.073492 -0.055554 0.073492 +v 0.081660 -0.077165 0.081660 +v 0.086690 -0.100614 0.086690 +v 0.088388 -0.125000 0.088388 +v 0.086690 -0.149386 0.086690 +v 0.081660 -0.172835 0.081660 +v 0.073492 -0.194446 0.073492 +v 0.062500 -0.213388 0.062500 +v 0.049106 -0.228934 0.049106 +v 0.033825 -0.240485 0.033825 +v 0.017244 -0.247598 0.017244 +v 0.013548 -0.002402 0.020277 +v 0.026576 -0.009515 0.039774 +v 0.038582 -0.021066 0.057743 +v 0.049106 -0.036612 0.073492 +v 0.057742 -0.055554 0.086418 +v 0.064160 -0.077165 0.096022 +v 0.068112 -0.100614 0.101937 +v 0.069446 -0.125000 0.103934 +v 0.068112 -0.149386 0.101937 +v 0.064160 -0.172835 0.096022 +v 0.057742 -0.194446 0.086418 +v 0.049106 -0.213388 0.073492 +v 0.038582 -0.228934 0.057743 +v 0.026576 -0.240485 0.039774 +v 0.013548 -0.247598 0.020277 +v 0.000000 -0.250000 0.000000 +v 0.009332 -0.002402 0.022530 +v 0.018306 -0.009515 0.044194 +v 0.026576 -0.021066 0.064160 +v 0.033825 -0.036612 0.081660 +v 0.039774 -0.055554 0.096022 +v 0.044194 -0.077165 0.106694 +v 0.046916 -0.100614 0.113266 +v 0.047835 -0.125000 0.115485 +v 0.046916 -0.149386 0.113266 +v 0.044194 -0.172835 0.106694 +v 0.039774 -0.194446 0.096022 +v 0.033825 -0.213388 0.081660 +v 0.026576 -0.228934 0.064160 +v 0.018306 -0.240485 0.044194 +v 0.009332 -0.247598 0.022530 +v 0.004758 -0.002402 0.023918 +v 0.009332 -0.009515 0.046916 +v 0.013548 -0.021066 0.068112 +v 0.017244 -0.036612 0.086690 +v 0.020276 -0.055554 0.101937 +v 0.022530 -0.077165 0.113266 +v 0.023918 -0.100614 0.120242 +v 0.024386 -0.125000 0.122598 +v 0.023918 -0.149386 0.120242 +v 0.022530 -0.172835 0.113266 +v 0.020276 -0.194446 0.101937 +v 0.017244 -0.213388 0.086690 +v 0.013548 -0.228934 0.068112 +v 0.009332 -0.240485 0.046916 +v 0.004758 -0.247598 0.023918 +v -0.000000 -0.002402 0.024386 +v 0.000000 -0.009515 0.047835 +v 0.000000 -0.021066 0.069446 +v -0.000000 -0.036612 0.088388 +v -0.000000 -0.055554 0.103934 +v 0.000000 -0.077165 0.115485 +v -0.000000 -0.100614 0.122598 +v -0.000000 -0.125000 0.125000 +v -0.000000 -0.149386 0.122598 +v 0.000000 -0.172835 0.115485 +v -0.000000 -0.194446 0.103934 +v -0.000000 -0.213388 0.088388 +v -0.000000 -0.228934 0.069446 +v 0.000000 -0.240485 0.047835 +v 0.000000 -0.247598 0.024386 +v -0.004758 -0.002402 0.023918 +v -0.009332 -0.009515 0.046916 +v -0.013548 -0.021066 0.068112 +v -0.017244 -0.036612 0.086690 +v -0.020276 -0.055554 0.101937 +v -0.022530 -0.077165 0.113266 +v -0.023918 -0.100614 0.120242 +v -0.024386 -0.125000 0.122598 +v -0.023918 -0.149386 0.120242 +v -0.022530 -0.172835 0.113266 +v -0.020276 -0.194446 0.101937 +v -0.017244 -0.213388 0.086690 +v -0.013548 -0.228934 0.068112 +v -0.009332 -0.240485 0.046916 +v -0.004758 -0.247598 0.023918 +v -0.009332 -0.002402 0.022530 +v -0.018306 -0.009515 0.044194 +v -0.026576 -0.021066 0.064160 +v -0.033825 -0.036612 0.081660 +v -0.039774 -0.055554 0.096022 +v -0.044194 -0.077165 0.106694 +v -0.046916 -0.100614 0.113266 +v -0.047835 -0.125000 0.115485 +v -0.046916 -0.149386 0.113266 +v -0.044194 -0.172835 0.106694 +v -0.039774 -0.194446 0.096022 +v -0.033825 -0.213388 0.081660 +v -0.026576 -0.228934 0.064160 +v -0.018306 -0.240485 0.044194 +v -0.009332 -0.247598 0.022530 +v -0.013548 -0.002402 0.020277 +v -0.026576 -0.009515 0.039774 +v -0.038582 -0.021066 0.057743 +v -0.049106 -0.036612 0.073492 +v -0.057742 -0.055554 0.086418 +v -0.064160 -0.077165 0.096022 +v -0.068112 -0.100614 0.101937 +v -0.069446 -0.125000 0.103934 +v -0.068112 -0.149386 0.101937 +v -0.064160 -0.172835 0.096022 +v -0.057742 -0.194446 0.086418 +v -0.049106 -0.213388 0.073492 +v -0.038582 -0.228934 0.057742 +v -0.026576 -0.240485 0.039774 +v -0.013548 -0.247598 0.020276 +v -0.000000 0.000000 0.000000 +v -0.017244 -0.002402 0.017244 +v -0.033825 -0.009515 0.033825 +v -0.049106 -0.021066 0.049106 +v -0.062500 -0.036612 0.062500 +v -0.073492 -0.055554 0.073492 +v -0.081660 -0.077165 0.081660 +v -0.086690 -0.100614 0.086690 +v -0.088388 -0.125000 0.088388 +v -0.086690 -0.149386 0.086690 +v -0.081660 -0.172835 0.081660 +v -0.073492 -0.194446 0.073492 +v -0.062500 -0.213388 0.062500 +v -0.049106 -0.228934 0.049106 +v -0.033825 -0.240485 0.033825 +v -0.017244 -0.247598 0.017244 +v -0.020276 -0.002402 0.013548 +v -0.039774 -0.009515 0.026576 +v -0.057742 -0.021066 0.038582 +v -0.073492 -0.036612 0.049106 +v -0.086418 -0.055554 0.057742 +v -0.096022 -0.077165 0.064160 +v -0.101937 -0.100614 0.068112 +v -0.103934 -0.125000 0.069446 +v -0.101937 -0.149386 0.068112 +v -0.096022 -0.172835 0.064160 +v -0.086418 -0.194446 0.057742 +v -0.073492 -0.213388 0.049106 +v -0.057742 -0.228934 0.038582 +v -0.039774 -0.240485 0.026576 +v -0.020276 -0.247598 0.013548 +v -0.022530 -0.002402 0.009332 +v -0.044194 -0.009515 0.018306 +v -0.064160 -0.021066 0.026576 +v -0.081660 -0.036612 0.033825 +v -0.096022 -0.055554 0.039774 +v -0.106694 -0.077165 0.044194 +v -0.113266 -0.100614 0.046916 +v -0.115485 -0.125000 0.047835 +v -0.113266 -0.149386 0.046916 +v -0.106694 -0.172835 0.044194 +v -0.096022 -0.194446 0.039774 +v -0.081660 -0.213388 0.033825 +v -0.064160 -0.228934 0.026576 +v -0.044194 -0.240485 0.018306 +v -0.022530 -0.247598 0.009332 +v -0.023918 -0.002402 0.004758 +v -0.046916 -0.009515 0.009332 +v -0.068112 -0.021066 0.013548 +v -0.086690 -0.036612 0.017244 +v -0.101937 -0.055554 0.020276 +v -0.113266 -0.077165 0.022530 +v -0.120242 -0.100614 0.023918 +v -0.122598 -0.125000 0.024386 +v -0.120242 -0.149386 0.023918 +v -0.113266 -0.172835 0.022530 +v -0.101937 -0.194446 0.020276 +v -0.086690 -0.213388 0.017244 +v -0.068112 -0.228934 0.013548 +v -0.046916 -0.240485 0.009332 +v -0.023918 -0.247598 0.004758 +v -0.024386 -0.002402 0.000000 +v -0.047835 -0.009515 0.000000 +v -0.069446 -0.021066 0.000000 +v -0.088388 -0.036612 0.000000 +v -0.103934 -0.055554 0.000000 +v -0.115485 -0.077165 0.000000 +v -0.122598 -0.100614 0.000000 +v -0.125000 -0.125000 0.000000 +v -0.122598 -0.149386 0.000000 +v -0.115485 -0.172835 0.000000 +v -0.103934 -0.194446 0.000000 +v -0.088388 -0.213388 0.000000 +v -0.069446 -0.228934 0.000000 +v -0.047835 -0.240485 0.000000 +v -0.024386 -0.247598 0.000000 +v -0.023918 -0.002402 -0.004757 +v -0.046916 -0.009515 -0.009332 +v -0.068112 -0.021066 -0.013548 +v -0.086690 -0.036612 -0.017244 +v -0.101937 -0.055554 -0.020276 +v -0.113266 -0.077165 -0.022530 +v -0.120242 -0.100614 -0.023918 +v -0.122598 -0.125000 -0.024386 +v -0.120242 -0.149386 -0.023918 +v -0.113266 -0.172835 -0.022530 +v -0.101937 -0.194446 -0.020276 +v -0.086690 -0.213388 -0.017244 +v -0.068112 -0.228934 -0.013548 +v -0.046916 -0.240485 -0.009332 +v -0.023918 -0.247598 -0.004757 +v -0.022530 -0.002402 -0.009332 +v -0.044194 -0.009515 -0.018306 +v -0.064160 -0.021066 -0.026576 +v -0.081660 -0.036612 -0.033825 +v -0.096022 -0.055554 -0.039774 +v -0.106694 -0.077165 -0.044194 +v -0.113266 -0.100614 -0.046916 +v -0.115485 -0.125000 -0.047835 +v -0.113266 -0.149386 -0.046916 +v -0.106694 -0.172835 -0.044194 +v -0.096022 -0.194446 -0.039774 +v -0.081660 -0.213388 -0.033825 +v -0.064160 -0.228934 -0.026576 +v -0.044194 -0.240485 -0.018306 +v -0.022530 -0.247598 -0.009332 +v -0.020276 -0.002402 -0.013548 +v -0.039774 -0.009515 -0.026576 +v -0.057742 -0.021066 -0.038582 +v -0.073492 -0.036612 -0.049106 +v -0.086418 -0.055554 -0.057742 +v -0.096022 -0.077165 -0.064160 +v -0.101937 -0.100614 -0.068112 +v -0.103934 -0.125000 -0.069446 +v -0.101937 -0.149386 -0.068112 +v -0.096022 -0.172835 -0.064160 +v -0.086418 -0.194446 -0.057742 +v -0.073492 -0.213388 -0.049106 +v -0.057742 -0.228934 -0.038582 +v -0.039774 -0.240485 -0.026576 +v -0.020276 -0.247598 -0.013548 +v -0.017244 -0.002402 -0.017244 +v -0.033825 -0.009515 -0.033825 +v -0.049106 -0.021066 -0.049106 +v -0.062500 -0.036612 -0.062500 +v -0.073492 -0.055554 -0.073492 +v -0.081660 -0.077165 -0.081660 +v -0.086690 -0.100614 -0.086690 +v -0.088388 -0.125000 -0.088388 +v -0.086690 -0.149386 -0.086690 +v -0.081660 -0.172835 -0.081660 +v -0.073492 -0.194446 -0.073492 +v -0.062500 -0.213388 -0.062500 +v -0.049106 -0.228934 -0.049106 +v -0.033825 -0.240485 -0.033825 +v -0.017244 -0.247598 -0.017244 +v -0.013548 -0.002402 -0.020276 +v -0.026576 -0.009515 -0.039774 +v -0.038582 -0.021066 -0.057742 +v -0.049106 -0.036612 -0.073492 +v -0.057742 -0.055554 -0.086418 +v -0.064160 -0.077165 -0.096022 +v -0.068112 -0.100614 -0.101937 +v -0.069446 -0.125000 -0.103934 +v -0.068112 -0.149386 -0.101937 +v -0.064160 -0.172835 -0.096022 +v -0.057742 -0.194446 -0.086418 +v -0.049106 -0.213388 -0.073492 +v -0.038582 -0.228934 -0.057742 +v -0.026576 -0.240485 -0.039774 +v -0.013548 -0.247598 -0.020276 +v -0.009332 -0.002402 -0.022530 +v -0.018306 -0.009515 -0.044194 +v -0.026576 -0.021066 -0.064160 +v -0.033825 -0.036612 -0.081660 +v -0.039774 -0.055554 -0.096022 +v -0.044194 -0.077165 -0.106694 +v -0.046916 -0.100614 -0.113266 +v -0.047835 -0.125000 -0.115485 +v -0.046916 -0.149386 -0.113266 +v -0.044194 -0.172835 -0.106694 +v -0.039774 -0.194446 -0.096022 +v -0.033825 -0.213388 -0.081660 +v -0.026576 -0.228934 -0.064160 +v -0.018306 -0.240485 -0.044194 +v -0.009332 -0.247598 -0.022530 +v -0.004758 -0.002402 -0.023918 +v -0.009332 -0.009515 -0.046916 +v -0.013548 -0.021066 -0.068112 +v -0.017244 -0.036612 -0.086690 +v -0.020276 -0.055554 -0.101937 +v -0.022530 -0.077165 -0.113266 +v -0.023918 -0.100614 -0.120242 +v -0.024386 -0.125000 -0.122598 +v -0.023918 -0.149386 -0.120242 +v -0.022530 -0.172835 -0.113266 +v -0.020276 -0.194446 -0.101937 +v -0.017244 -0.213388 -0.086690 +v -0.013548 -0.228934 -0.068112 +v -0.009332 -0.240485 -0.046916 +v -0.004758 -0.247598 -0.023918 +v 0.000000 -0.172835 -0.115485 +v 0.000000 -0.194446 -0.103934 +v 0.000000 -0.213388 -0.088388 +v 0.000000 -0.240485 -0.047835 +v 0.000000 -0.247598 -0.024386 +vt 0.668772 0.339905 +vt 0.689230 0.360743 +vt 0.669184 0.377746 +vt 0.651681 0.356229 +vt 0.389163 0.202579 +vt 0.362996 0.217196 +vt 0.354467 0.203069 +vt 0.377271 0.185807 +vt 0.646681 0.320659 +vt 0.633008 0.335578 +vt 0.413677 0.185991 +vt 0.398545 0.167533 +vt 0.622926 0.303143 +vt 0.612891 0.315762 +vt 0.436588 0.167587 +vt 0.418601 0.148246 +vt 0.597548 0.287432 +vt 0.591132 0.296771 +vt 0.458023 0.147603 +vt 0.437837 0.127926 +vt 0.570644 0.273504 +vt 0.567617 0.278601 +vt 0.478275 0.126406 +vt 0.456847 0.106512 +vt 0.305589 0.240241 +vt 0.274071 0.248522 +vt 0.303203 0.234492 +vt 0.542292 0.261250 +vt 0.708194 0.382963 +vt 0.726005 0.406260 +vt 0.702401 0.423755 +vt 0.685896 0.400205 +vt 0.335155 0.229756 +vt 0.329861 0.219303 +vt 0.663172 0.415515 +vt 0.648629 0.392409 +vt 0.323071 0.210092 +vt 0.344338 0.190783 +vt 0.633758 0.370044 +vt 0.363989 0.171294 +vt 0.618149 0.348117 +vt 0.382403 0.151482 +vt 0.601457 0.326404 +vt 0.399978 0.131162 +vt 0.583389 0.304743 +vt 0.417177 0.110087 +vt 0.563718 0.283032 +vt 0.434588 0.087911 +vt 0.299830 0.229324 +vt 0.677930 0.439801 +vt 0.588867 0.335092 +vt 0.574555 0.311248 +vt 0.380492 0.116148 +vt 0.395679 0.094118 +vt 0.559087 0.286667 +vt 0.411285 0.070977 +vt 0.295606 0.224884 +vt 0.652447 0.453972 +vt 0.639692 0.428795 +vt 0.315020 0.202234 +vt 0.627341 0.404858 +vt 0.332858 0.180314 +vt 0.614973 0.381555 +vt 0.349473 0.158868 +vt 0.602248 0.358424 +vt 0.365227 0.137595 +vt 0.305914 0.195823 +vt 0.320206 0.171664 +vt 0.605219 0.415133 +vt 0.595309 0.390853 +vt 0.333813 0.148443 +vt 0.585400 0.366570 +vt 0.346997 0.125748 +vt 0.575302 0.341820 +vt 0.360029 0.103127 +vt 0.564843 0.316200 +vt 0.373209 0.080066 +vt 0.553878 0.289397 +vt 0.386907 0.055924 +vt 0.290677 0.221292 +vt 0.625970 0.466029 +vt 0.615350 0.439958 +vt 0.338534 0.092053 +vt 0.349744 0.067938 +vt 0.554450 0.319516 +vt 0.548253 0.291138 +vt 0.361527 0.042845 +vt 0.285201 0.218644 +vt 0.598611 0.475863 +vt 0.590142 0.448972 +vt 0.295936 0.190947 +vt 0.582222 0.423250 +vt 0.306517 0.164866 +vt 0.574753 0.397969 +vt 0.317063 0.139995 +vt 0.567667 0.372561 +vt 0.327692 0.115886 +vt 0.560912 0.346549 +vt 0.558307 0.429239 +vt 0.553277 0.402895 +vt 0.291900 0.159996 +vt 0.299242 0.133555 +vt 0.549089 0.376349 +vt 0.307269 0.107991 +vt 0.545827 0.349198 +vt 0.315959 0.082871 +vt 0.543571 0.321107 +vt 0.325296 0.057677 +vt 0.542388 0.291828 +vt 0.335284 0.031720 +vt 0.279342 0.217017 +vt 0.570531 0.483497 +vt 0.564093 0.455881 +vt 0.285266 0.187700 +vt 0.532418 0.320875 +vt 0.536469 0.291426 +vt 0.299855 0.049111 +vt 0.308360 0.022381 +vt 0.273275 0.216467 +vt 0.541920 0.489120 +vt 0.537178 0.460846 +vt 0.274090 0.186190 +vt 0.533366 0.433155 +vt 0.276456 0.157179 +vt 0.530795 0.405581 +vt 0.280338 0.129215 +vt 0.529677 0.377815 +vt 0.285630 0.102075 +vt 0.530176 0.349635 +vt 0.292196 0.075493 +vt 0.260296 0.156605 +vt 0.260296 0.127156 +vt 0.507124 0.405903 +vt 0.509417 0.376745 +vt 0.262576 0.098207 +vt 0.514114 0.347662 +vt 0.266993 0.069785 +vt 0.521233 0.318712 +vt 0.273284 0.041887 +vt 0.530693 0.289920 +vt 0.280981 0.014424 +vt 0.267186 0.217028 +vt 0.512983 0.493192 +vt 0.509189 0.464218 +vt 0.262617 0.186536 +vt 0.507124 0.435075 +vt 0.478275 0.389352 +vt 0.458023 0.410549 +vt 0.437837 0.390872 +vt 0.456847 0.369458 +vt 0.305590 0.503188 +vt 0.274071 0.511469 +vt 0.303203 0.497438 +vt 0.478275 0.575178 +vt 0.466108 0.603512 +vt 0.461011 0.600503 +vt 0.357244 0.741258 +vt 0.334067 0.759173 +vt 0.316446 0.735681 +vt 0.339906 0.719060 +vt 0.335155 0.492703 +vt 0.329861 0.482249 +vt 0.379353 0.722215 +vt 0.362280 0.702258 +vt 0.362996 0.480142 +vt 0.354467 0.466015 +vt 0.400085 0.701700 +vt 0.383716 0.684686 +vt 0.389163 0.465525 +vt 0.377271 0.448753 +vt 0.419231 0.679571 +vt 0.404285 0.665961 +vt 0.413677 0.448937 +vt 0.398545 0.430479 +vt 0.436650 0.655795 +vt 0.424019 0.645809 +vt 0.436588 0.430533 +vt 0.418601 0.411192 +vt 0.452269 0.630411 +vt 0.442927 0.624028 +vt 0.369847 0.666822 +vt 0.391713 0.651154 +vt 0.363990 0.434240 +vt 0.382403 0.414428 +vt 0.413358 0.634418 +vt 0.399978 0.394108 +vt 0.434946 0.616316 +vt 0.417176 0.373033 +vt 0.456578 0.596621 +vt 0.434588 0.350856 +vt 0.299830 0.492271 +vt 0.300261 0.711288 +vt 0.324490 0.696407 +vt 0.323071 0.473038 +vt 0.347540 0.681767 +vt 0.344338 0.453729 +vt 0.452938 0.592006 +vt 0.285945 0.685844 +vt 0.311102 0.672966 +vt 0.295606 0.487831 +vt 0.315021 0.465181 +vt 0.335012 0.660520 +vt 0.332858 0.443260 +vt 0.358281 0.648079 +vt 0.349473 0.421814 +vt 0.381368 0.635294 +vt 0.365227 0.400541 +vt 0.404647 0.621863 +vt 0.380492 0.379094 +vt 0.428428 0.607510 +vt 0.395678 0.357064 +vt 0.411284 0.333923 +vt 0.373184 0.618476 +vt 0.397893 0.608329 +vt 0.346997 0.388694 +vt 0.360029 0.366073 +vt 0.423460 0.597822 +vt 0.373209 0.343012 +vt 0.450200 0.586811 +vt 0.386906 0.318870 +vt 0.290678 0.484238 +vt 0.273749 0.659366 +vt 0.299836 0.648633 +vt 0.305914 0.458770 +vt 0.324662 0.638417 +vt 0.320206 0.434610 +vt 0.348930 0.628440 +vt 0.333813 0.411389 +vt 0.285201 0.481590 +vt 0.295937 0.453893 +vt 0.290734 0.623405 +vt 0.316479 0.615416 +vt 0.306517 0.427812 +vt 0.341772 0.607897 +vt 0.317063 0.402941 +vt 0.367159 0.600767 +vt 0.327692 0.378832 +vt 0.393137 0.593964 +vt 0.338534 0.355000 +vt 0.420125 0.587451 +vt 0.349744 0.330884 +vt 0.448449 0.581199 +vt 0.361527 0.305791 +vt 0.263791 0.631962 +vt 0.307269 0.370937 +vt 0.315958 0.345818 +vt 0.390461 0.578901 +vt 0.418512 0.576591 +vt 0.325296 0.320623 +vt 0.447747 0.575345 +vt 0.335283 0.294666 +vt 0.279342 0.479964 +vt 0.256065 0.603793 +vt 0.283767 0.597314 +vt 0.285267 0.450647 +vt 0.310443 0.591495 +vt 0.291900 0.422942 +vt 0.336815 0.586433 +vt 0.299242 0.396501 +vt 0.363341 0.582209 +vt 0.278797 0.570347 +vt 0.306518 0.566554 +vt 0.274090 0.449137 +vt 0.276456 0.420125 +vt 0.334106 0.563971 +vt 0.280338 0.392161 +vt 0.361847 0.562818 +vt 0.285630 0.365021 +vt 0.389996 0.563270 +vt 0.292195 0.338439 +vt 0.418721 0.565454 +vt 0.299855 0.312058 +vt 0.448135 0.569434 +vt 0.308359 0.285328 +vt 0.273275 0.479414 +vt 0.250405 0.575044 +vt 0.391939 0.547227 +vt 0.420859 0.554281 +vt 0.266993 0.332732 +vt 0.273284 0.304833 +vt 0.449626 0.563665 +vt 0.280980 0.277371 +vt 0.267187 0.479974 +vt 0.246401 0.545909 +vt 0.275509 0.542335 +vt 0.262617 0.449483 +vt 0.304623 0.540317 +vt 0.260296 0.419552 +vt 0.333769 0.540318 +vt 0.260296 0.390103 +vt 0.362891 0.542580 +vt 0.262575 0.361154 +vt 0.761811 0.347681 +vt 0.768908 0.318727 +vt 0.780094 0.320881 +vt 0.777874 0.349643 +vt 0.564347 0.675320 +vt 0.543898 0.654488 +vt 0.563946 0.637492 +vt 0.581435 0.658999 +vt 0.757134 0.376765 +vt 0.777395 0.377824 +vt 0.586437 0.694569 +vt 0.600112 0.679650 +vt 0.754853 0.405922 +vt 0.778527 0.405595 +vt 0.610192 0.712088 +vt 0.620229 0.699470 +vt 0.754853 0.435093 +vt 0.781108 0.433185 +vt 0.635570 0.727802 +vt 0.641987 0.718463 +vt 0.756891 0.464239 +vt 0.784920 0.460921 +vt 0.662473 0.741731 +vt 0.665500 0.736635 +vt 0.760508 0.493374 +vt 0.789651 0.489316 +vt 0.778345 0.289928 +vt 0.789919 0.261250 +vt 0.784121 0.291430 +vt 0.690823 0.753987 +vt 0.524935 0.632265 +vt 0.507124 0.608964 +vt 0.530732 0.591469 +vt 0.547237 0.615024 +vt 0.806069 0.429255 +vt 0.811888 0.455932 +vt 0.649731 0.710492 +vt 0.669399 0.732204 +vt 0.818384 0.483616 +vt 0.790041 0.291827 +vt 0.555208 0.575421 +vt 0.569968 0.599712 +vt 0.791247 0.321105 +vt 0.584515 0.622824 +vt 0.793525 0.349194 +vt 0.599366 0.645177 +vt 0.796808 0.376345 +vt 0.614975 0.667111 +vt 0.801016 0.402895 +vt 0.631664 0.688828 +vt 0.605807 0.610369 +vt 0.618159 0.633668 +vt 0.808608 0.346533 +vt 0.815385 0.372542 +vt 0.630879 0.656805 +vt 0.822496 0.397949 +vt 0.644257 0.680142 +vt 0.829996 0.423234 +vt 0.658565 0.703988 +vt 0.837962 0.448965 +vt 0.674030 0.728570 +vt 0.846513 0.475871 +vt 0.795905 0.291132 +vt 0.580696 0.561249 +vt 0.593452 0.586430 +vt 0.802124 0.319505 +vt 0.668278 0.699037 +vt 0.679240 0.725841 +vt 0.863157 0.439887 +vt 0.873856 0.465923 +vt 0.801527 0.289386 +vt 0.607176 0.549193 +vt 0.617796 0.575265 +vt 0.812514 0.316180 +vt 0.627928 0.600091 +vt 0.822994 0.341792 +vt 0.637829 0.624374 +vt 0.833114 0.366534 +vt 0.647731 0.648663 +vt 0.843047 0.390809 +vt 0.657823 0.673416 +vt 0.852991 0.415079 +vt 0.658390 0.617269 +vt 0.665465 0.642677 +vt 0.849954 0.358372 +vt 0.862699 0.381487 +vt 0.672213 0.668690 +vt 0.875090 0.404766 +vt 0.678671 0.695722 +vt 0.887452 0.428664 +vt 0.684864 0.724100 +vt 0.900261 0.453770 +vt 0.806735 0.286652 +vt 0.634536 0.539361 +vt 0.643004 0.566251 +vt 0.822222 0.311220 +vt 0.650928 0.591972 +vt 0.836553 0.335052 +vt 0.811362 0.283014 +vt 0.690729 0.723410 +vt 0.662613 0.531730 +vt 0.669050 0.559341 +vt 0.831050 0.304708 +vt 0.674839 0.585978 +vt 0.849136 0.326354 +vt 0.679866 0.612354 +vt 0.865844 0.348051 +vt 0.684042 0.638896 +vt 0.881467 0.369960 +vt 0.687298 0.666044 +vt 0.896347 0.392297 +vt 0.689549 0.694133 +vt 0.910870 0.415352 +vt 0.925629 0.439546 +vt 0.880692 0.335502 +vt 0.899375 0.356137 +vt 0.703451 0.637435 +vt 0.702946 0.665609 +vt 0.916877 0.377637 +vt 0.700701 0.694366 +vt 0.933539 0.400050 +vt 0.696648 0.723813 +vt 0.949961 0.423523 +vt 0.815258 0.278580 +vt 0.691218 0.526109 +vt 0.695958 0.554375 +vt 0.838787 0.296729 +vt 0.699773 0.582056 +vt 0.860562 0.315703 +vt 0.702344 0.609678 +vt 0.720145 0.522040 +vt 0.723936 0.551005 +vt 0.818280 0.273480 +vt 0.845196 0.287385 +vt 0.725999 0.580136 +vt 0.870586 0.303076 +vt 0.725999 0.609363 +vt 0.894356 0.320575 +vt 0.723704 0.638508 +vt 0.916459 0.339810 +vt 0.719005 0.667584 +vt 0.936922 0.360645 +vt 0.711884 0.696530 +vt 0.955850 0.382862 +vt 0.702423 0.725319 +vt 0.973431 0.406172 +vt 0.599044 0.014424 +vt 0.628498 0.014424 +vt 0.626437 0.034472 +vt 0.598469 0.030587 +vt 0.189946 0.171162 +vt 0.167327 0.188875 +vt 0.152666 0.170621 +vt 0.172639 0.151935 +vt 0.569110 0.016746 +vt 0.569456 0.028219 +vt 0.211232 0.152027 +vt 0.191935 0.132356 +vt 0.538618 0.021316 +vt 0.539178 0.027405 +vt 0.231447 0.131881 +vt 0.211109 0.111861 +vt 0.061469 0.242777 +vt 0.030595 0.252304 +vt 0.058935 0.237166 +vt 0.507124 0.028202 +vt 0.713744 0.027395 +vt 0.741217 0.035092 +vt 0.733260 0.062481 +vt 0.706520 0.053978 +vt 0.090334 0.231872 +vt 0.084975 0.221653 +vt 0.685832 0.021104 +vt 0.680127 0.046323 +vt 0.117564 0.219306 +vt 0.109119 0.205449 +vt 0.657458 0.016705 +vt 0.653584 0.039773 +vt 0.143219 0.204965 +vt 0.131596 0.188451 +vt 0.055439 0.232139 +vt 0.078137 0.212633 +vt 0.697957 0.079428 +vt 0.672754 0.070095 +vt 0.099071 0.193344 +vt 0.647660 0.061415 +vt 0.118548 0.174069 +vt 0.622094 0.053379 +vt 0.136924 0.154618 +vt 0.595651 0.046032 +vt 0.154589 0.134786 +vt 0.567945 0.039396 +vt 0.172025 0.114329 +vt 0.538628 0.033472 +vt 0.189792 0.092919 +vt 0.723921 0.089414 +vt 0.120057 0.140650 +vt 0.135553 0.119561 +vt 0.590779 0.060649 +vt 0.564698 0.050066 +vt 0.151126 0.098002 +vt 0.537002 0.039331 +vt 0.167257 0.075451 +vt 0.051111 0.227840 +vt 0.712797 0.115663 +vt 0.687699 0.103882 +vt 0.070041 0.204930 +vt 0.663578 0.092677 +vt 0.087646 0.182986 +vt 0.639757 0.081836 +vt 0.104208 0.161672 +vt 0.615649 0.071200 +vt 0.675575 0.127351 +vt 0.652510 0.114176 +vt 0.060878 0.198647 +vt 0.075006 0.174391 +vt 0.629889 0.101138 +vt 0.088649 0.151197 +vt 0.607197 0.087948 +vt 0.102027 0.128623 +vt 0.583980 0.074337 +vt 0.115399 0.106210 +vt 0.559822 0.060043 +vt 0.129082 0.083446 +vt 0.534354 0.044807 +vt 0.143445 0.059697 +vt 0.046092 0.224391 +vt 0.699719 0.141045 +vt 0.575328 0.086988 +vt 0.553411 0.069149 +vt 0.094059 0.094708 +vt 0.105856 0.070698 +vt 0.530762 0.049736 +vt 0.118411 0.045782 +vt 0.040536 0.221892 +vt 0.684668 0.165423 +vt 0.661528 0.149822 +vt 0.050824 0.193883 +vt 0.639496 0.134643 +vt 0.061274 0.167614 +vt 0.618037 0.119363 +vt 0.071908 0.142643 +vt 0.596769 0.103605 +vt 0.082798 0.118505 +vt 0.624491 0.154131 +vt 0.604145 0.136532 +vt 0.046550 0.162751 +vt 0.053993 0.136069 +vt 0.584342 0.118117 +vt 0.062309 0.110309 +vt 0.564860 0.098465 +vt 0.071461 0.085035 +vt 0.545554 0.077199 +vt 0.081442 0.059742 +vt 0.526322 0.053960 +vt 0.092269 0.033725 +vt 0.034607 0.220421 +vt 0.667740 0.188724 +vt 0.645566 0.171320 +vt 0.040051 0.190748 +vt 0.536344 0.083989 +vt 0.521155 0.057333 +vt 0.055798 0.050439 +vt 0.065182 0.023397 +vt 0.028480 0.220039 +vt 0.649146 0.210979 +vt 0.627736 0.191978 +vt 0.028743 0.189363 +vt 0.607418 0.172754 +vt 0.030929 0.159948 +vt 0.588093 0.152664 +vt 0.034881 0.131594 +vt 0.569830 0.131393 +vt 0.040449 0.104080 +vt 0.552575 0.108592 +vt 0.047477 0.077142 +vt 0.014424 0.159388 +vt 0.014424 0.129394 +vt 0.569644 0.167783 +vt 0.553064 0.143280 +vt 0.016940 0.099886 +vt 0.538450 0.117119 +vt 0.021811 0.070899 +vt 0.525891 0.089282 +vt 0.028776 0.042442 +vt 0.515406 0.059719 +vt 0.037375 0.014424 +vt 0.022300 0.220775 +vt 0.629261 0.232402 +vt 0.608070 0.212158 +vt 0.017030 0.189838 +vt 0.588093 0.190735 +vn 0.0000 -0.5528 -0.8333 +vn 0.0000 -0.3805 -0.9247 +vn 0.1804 -0.3805 -0.9070 +vn 0.1626 -0.5528 -0.8173 +vn 0.0000 0.7040 -0.7101 +vn 0.0000 0.8286 -0.5598 +vn 0.1092 0.8286 -0.5490 +vn 0.1385 0.7040 -0.6965 +vn 0.0000 -0.7040 -0.7101 +vn 0.1385 -0.7040 -0.6965 +vn 0.0000 0.5528 -0.8333 +vn 0.1626 0.5528 -0.8173 +vn 0.0000 -0.8286 -0.5598 +vn 0.1092 -0.8286 -0.5490 +vn 0.0000 0.3805 -0.9247 +vn 0.1804 0.3805 -0.9070 +vn 0.0000 -0.9217 -0.3879 +vn 0.0757 -0.9217 -0.3804 +vn 0.0000 0.1939 -0.9810 +vn 0.1914 0.1939 -0.9622 +vn 0.0000 -0.9796 -0.2010 +vn 0.0392 -0.9796 -0.1971 +vn 0.0000 0.0000 -1.0000 +vn 0.1951 0.0000 -0.9808 +vn 0.0000 0.9796 -0.2010 +vn 0.0000 1.0000 0.0000 +vn 0.0392 0.9796 -0.1971 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 -0.1939 -0.9810 +vn 0.1914 -0.1939 -0.9622 +vn 0.0000 0.9217 -0.3879 +vn 0.0757 0.9217 -0.3804 +vn 0.3754 -0.1939 -0.9063 +vn 0.3539 -0.3805 -0.8544 +vn 0.1484 0.9217 -0.3583 +vn 0.2142 0.8286 -0.5171 +vn 0.3189 -0.5528 -0.7699 +vn 0.2717 0.7040 -0.6561 +vn 0.2717 -0.7040 -0.6561 +vn 0.3189 0.5528 -0.7699 +vn 0.2142 -0.8286 -0.5171 +vn 0.3539 0.3805 -0.8544 +vn 0.1484 -0.9217 -0.3583 +vn 0.3754 0.1939 -0.9063 +vn 0.0769 -0.9796 -0.1856 +vn 0.3827 0.0000 -0.9239 +vn 0.0769 0.9796 -0.1856 +vn 0.3110 -0.8286 -0.4654 +vn 0.2155 -0.9217 -0.3225 +vn 0.5137 0.3805 -0.7689 +vn 0.5450 0.1939 -0.8157 +vn 0.1116 -0.9796 -0.1671 +vn 0.5556 0.0000 -0.8314 +vn 0.1116 0.9796 -0.1671 +vn 0.5450 -0.1939 -0.8157 +vn 0.2155 0.9217 -0.3225 +vn 0.5137 -0.3805 -0.7689 +vn 0.3110 0.8286 -0.4654 +vn 0.4630 -0.5528 -0.6929 +vn 0.3945 0.7040 -0.5904 +vn 0.3945 -0.7040 -0.5904 +vn 0.4630 0.5528 -0.6929 +vn 0.2743 0.9217 -0.2743 +vn 0.3958 0.8286 -0.3958 +vn 0.6539 -0.3805 -0.6539 +vn 0.5893 -0.5528 -0.5893 +vn 0.5021 0.7040 -0.5021 +vn 0.5021 -0.7040 -0.5021 +vn 0.5893 0.5528 -0.5893 +vn 0.3958 -0.8286 -0.3958 +vn 0.6539 0.3805 -0.6539 +vn 0.2743 -0.9217 -0.2743 +vn 0.6937 0.1939 -0.6937 +vn 0.1421 -0.9796 -0.1421 +vn 0.7071 0.0000 -0.7071 +vn 0.1421 0.9796 -0.1421 +vn 0.6937 -0.1939 -0.6937 +vn 0.7689 0.3805 -0.5137 +vn 0.8157 0.1939 -0.5450 +vn 0.3225 -0.9217 -0.2155 +vn 0.1671 -0.9796 -0.1116 +vn 0.8314 0.0000 -0.5556 +vn 0.1671 0.9796 -0.1116 +vn 0.8157 -0.1939 -0.5450 +vn 0.3225 0.9217 -0.2155 +vn 0.7689 -0.3805 -0.5137 +vn 0.4654 0.8286 -0.3110 +vn 0.6929 -0.5528 -0.4630 +vn 0.5904 0.7040 -0.3945 +vn 0.5904 -0.7040 -0.3945 +vn 0.6929 0.5528 -0.4630 +vn 0.4654 -0.8286 -0.3110 +vn 0.8544 -0.3805 -0.3539 +vn 0.7699 -0.5528 -0.3189 +vn 0.5171 0.8286 -0.2142 +vn 0.6561 0.7040 -0.2717 +vn 0.6561 -0.7040 -0.2717 +vn 0.7699 0.5528 -0.3189 +vn 0.5171 -0.8286 -0.2142 +vn 0.8544 0.3805 -0.3539 +vn 0.3583 -0.9217 -0.1484 +vn 0.9063 0.1939 -0.3754 +vn 0.1856 -0.9796 -0.0769 +vn 0.9239 0.0000 -0.3827 +vn 0.1856 0.9796 -0.0769 +vn 0.9063 -0.1939 -0.3754 +vn 0.3583 0.9217 -0.1484 +vn 0.3804 -0.9217 -0.0757 +vn 0.1971 -0.9796 -0.0392 +vn 0.9622 0.1939 -0.1914 +vn 0.9808 0.0000 -0.1951 +vn 0.1971 0.9796 -0.0392 +vn 0.9622 -0.1939 -0.1914 +vn 0.3804 0.9217 -0.0757 +vn 0.9070 -0.3805 -0.1804 +vn 0.5490 0.8286 -0.1092 +vn 0.8173 -0.5528 -0.1626 +vn 0.6965 0.7040 -0.1385 +vn 0.6965 -0.7040 -0.1385 +vn 0.8173 0.5528 -0.1626 +vn 0.5490 -0.8286 -0.1092 +vn 0.9070 0.3805 -0.1804 +vn 0.5598 0.8286 0.0000 +vn 0.7101 0.7040 0.0000 +vn 0.8333 -0.5528 0.0000 +vn 0.7101 -0.7040 0.0000 +vn 0.8333 0.5528 0.0000 +vn 0.5598 -0.8286 0.0000 +vn 0.9247 0.3805 0.0000 +vn 0.3879 -0.9217 0.0000 +vn 0.9810 0.1939 0.0000 +vn 0.2010 -0.9796 0.0000 +vn 1.0000 0.0000 0.0000 +vn 0.2010 0.9796 0.0000 +vn 0.9810 -0.1939 0.0000 +vn 0.3879 0.9217 0.0000 +vn 0.9247 -0.3805 0.0000 +vn 0.9622 0.1939 0.1914 +vn 0.9808 0.0000 0.1951 +vn 0.1971 0.9796 0.0392 +vn 0.1971 -0.9796 0.0392 +vn 0.9622 -0.1939 0.1914 +vn 0.3804 0.9217 0.0757 +vn 0.9070 -0.3805 0.1804 +vn 0.5490 0.8286 0.1092 +vn 0.8173 -0.5528 0.1626 +vn 0.6965 0.7040 0.1385 +vn 0.6965 -0.7040 0.1385 +vn 0.8173 0.5528 0.1626 +vn 0.5490 -0.8286 0.1092 +vn 0.9070 0.3805 0.1804 +vn 0.3804 -0.9217 0.0757 +vn 0.7699 -0.5528 0.3189 +vn 0.6561 -0.7040 0.2717 +vn 0.6561 0.7040 0.2717 +vn 0.7699 0.5528 0.3189 +vn 0.5171 -0.8286 0.2142 +vn 0.8544 0.3805 0.3539 +vn 0.3583 -0.9217 0.1484 +vn 0.9063 0.1939 0.3754 +vn 0.1856 -0.9796 0.0769 +vn 0.9239 0.0000 0.3827 +vn 0.1856 0.9796 0.0769 +vn 0.9063 -0.1939 0.3754 +vn 0.3583 0.9217 0.1484 +vn 0.8544 -0.3805 0.3539 +vn 0.5171 0.8286 0.2142 +vn 0.1671 -0.9796 0.1116 +vn 0.8314 0.0000 0.5556 +vn 0.8157 -0.1939 0.5450 +vn 0.1671 0.9796 0.1116 +vn 0.3225 0.9217 0.2155 +vn 0.7689 -0.3805 0.5137 +vn 0.4654 0.8286 0.3110 +vn 0.6929 -0.5528 0.4630 +vn 0.5904 0.7040 0.3945 +vn 0.5904 -0.7040 0.3945 +vn 0.6929 0.5528 0.4630 +vn 0.4654 -0.8286 0.3110 +vn 0.7689 0.3805 0.5137 +vn 0.3225 -0.9217 0.2155 +vn 0.8157 0.1939 0.5450 +vn 0.5021 -0.7040 0.5021 +vn 0.3958 -0.8286 0.3958 +vn 0.5893 0.5528 0.5893 +vn 0.6539 0.3805 0.6539 +vn 0.2743 -0.9217 0.2743 +vn 0.6937 0.1939 0.6937 +vn 0.1421 -0.9796 0.1421 +vn 0.7071 0.0000 0.7071 +vn 0.1421 0.9796 0.1421 +vn 0.6937 -0.1939 0.6937 +vn 0.2743 0.9217 0.2743 +vn 0.6539 -0.3805 0.6539 +vn 0.3958 0.8286 0.3958 +vn 0.5893 -0.5528 0.5893 +vn 0.5021 0.7040 0.5021 +vn 0.1116 0.9796 0.1671 +vn 0.2155 0.9217 0.3225 +vn 0.5450 -0.1939 0.8157 +vn 0.5137 -0.3805 0.7689 +vn 0.3110 0.8286 0.4654 +vn 0.4630 -0.5528 0.6929 +vn 0.3945 0.7040 0.5904 +vn 0.3945 -0.7040 0.5904 +vn 0.4630 0.5528 0.6929 +vn 0.3110 -0.8286 0.4654 +vn 0.5137 0.3805 0.7689 +vn 0.2155 -0.9217 0.3225 +vn 0.5450 0.1939 0.8157 +vn 0.1116 -0.9796 0.1671 +vn 0.5556 0.0000 0.8314 +vn 0.3189 0.5528 0.7699 +vn 0.3539 0.3805 0.8544 +vn 0.2142 -0.8286 0.5171 +vn 0.1484 -0.9217 0.3583 +vn 0.3754 0.1939 0.9063 +vn 0.0769 -0.9796 0.1856 +vn 0.3827 0.0000 0.9239 +vn 0.0769 0.9796 0.1856 +vn 0.3754 -0.1939 0.9063 +vn 0.1484 0.9217 0.3583 +vn 0.3539 -0.3805 0.8544 +vn 0.2142 0.8286 0.5171 +vn 0.3189 -0.5528 0.7699 +vn 0.2717 0.7040 0.6561 +vn 0.2717 -0.7040 0.6561 +vn 0.1914 -0.1939 0.9622 +vn 0.1804 -0.3805 0.9070 +vn 0.0757 0.9217 0.3804 +vn 0.1092 0.8286 0.5490 +vn 0.1626 -0.5528 0.8173 +vn 0.1385 0.7040 0.6965 +vn 0.1385 -0.7040 0.6965 +vn 0.1626 0.5528 0.8173 +vn 0.1092 -0.8286 0.5490 +vn 0.1804 0.3805 0.9070 +vn 0.0757 -0.9217 0.3804 +vn 0.1914 0.1939 0.9622 +vn 0.0392 -0.9796 0.1971 +vn 0.1951 0.0000 0.9808 +vn 0.0392 0.9796 0.1971 +vn 0.0000 -0.8286 0.5598 +vn 0.0000 -0.9217 0.3879 +vn 0.0000 0.3805 0.9247 +vn 0.0000 0.1939 0.9810 +vn 0.0000 -0.9796 0.2010 +vn 0.0000 0.0000 1.0000 +vn 0.0000 0.9796 0.2010 +vn 0.0000 -0.1939 0.9810 +vn 0.0000 0.9217 0.3879 +vn 0.0000 -0.3805 0.9247 +vn 0.0000 0.8286 0.5598 +vn 0.0000 -0.5528 0.8333 +vn 0.0000 0.7040 0.7101 +vn 0.0000 -0.7040 0.7101 +vn 0.0000 0.5528 0.8333 +vn -0.0757 0.9217 0.3804 +vn -0.1092 0.8286 0.5490 +vn -0.1804 -0.3805 0.9070 +vn -0.1626 -0.5528 0.8173 +vn -0.1385 0.7040 0.6965 +vn -0.1385 -0.7040 0.6965 +vn -0.1626 0.5528 0.8173 +vn -0.1092 -0.8286 0.5490 +vn -0.1804 0.3805 0.9070 +vn -0.0757 -0.9217 0.3804 +vn -0.1914 0.1939 0.9622 +vn -0.0392 -0.9796 0.1971 +vn -0.1951 0.0000 0.9808 +vn -0.0392 0.9796 0.1971 +vn -0.1914 -0.1939 0.9622 +vn -0.3539 0.3805 0.8544 +vn -0.3754 0.1939 0.9063 +vn -0.1484 -0.9217 0.3583 +vn -0.0769 -0.9796 0.1856 +vn -0.3827 0.0000 0.9239 +vn -0.0769 0.9796 0.1856 +vn -0.3754 -0.1939 0.9063 +vn -0.1484 0.9217 0.3583 +vn -0.3539 -0.3805 0.8544 +vn -0.2142 0.8286 0.5171 +vn -0.3189 -0.5528 0.7699 +vn -0.2717 0.7040 0.6561 +vn -0.2717 -0.7040 0.6561 +vn -0.3189 0.5528 0.7699 +vn -0.2142 -0.8286 0.5171 +vn -0.5137 -0.3805 0.7689 +vn -0.4630 -0.5528 0.6929 +vn -0.3110 0.8286 0.4654 +vn -0.3945 0.7040 0.5904 +vn -0.3945 -0.7040 0.5904 +vn -0.4630 0.5528 0.6929 +vn -0.3110 -0.8286 0.4654 +vn -0.5137 0.3805 0.7689 +vn -0.2155 -0.9217 0.3225 +vn -0.5450 0.1939 0.8157 +vn -0.1116 -0.9796 0.1671 +vn -0.5556 0.0000 0.8314 +vn -0.1116 0.9796 0.1671 +vn -0.5450 -0.1939 0.8157 +vn -0.2155 0.9217 0.3225 +vn -0.2743 -0.9217 0.2743 +vn -0.1421 -0.9796 0.1421 +vn -0.6937 0.1939 0.6937 +vn -0.7071 0.0000 0.7071 +vn -0.1421 0.9796 0.1421 +vn -0.6937 -0.1939 0.6937 +vn -0.2743 0.9217 0.2743 +vn -0.6539 -0.3805 0.6539 +vn -0.3958 0.8286 0.3958 +vn -0.5893 -0.5528 0.5893 +vn -0.5021 0.7040 0.5021 +vn -0.5021 -0.7040 0.5021 +vn -0.5893 0.5528 0.5893 +vn -0.3958 -0.8286 0.3958 +vn -0.6539 0.3805 0.6539 +vn -0.6929 -0.5528 0.4630 +vn -0.5904 -0.7040 0.3945 +vn -0.5904 0.7040 0.3945 +vn -0.6929 0.5528 0.4630 +vn -0.4654 -0.8286 0.3110 +vn -0.7689 0.3805 0.5137 +vn -0.3225 -0.9217 0.2155 +vn -0.8157 0.1939 0.5450 +vn -0.1671 -0.9796 0.1116 +vn -0.8314 0.0000 0.5556 +vn -0.1671 0.9796 0.1116 +vn -0.8157 -0.1939 0.5450 +vn -0.3225 0.9217 0.2155 +vn -0.7689 -0.3805 0.5137 +vn -0.4654 0.8286 0.3110 +vn -0.1856 0.9796 0.0769 +vn -0.1856 -0.9796 0.0769 +vn -0.9239 0.0000 0.3827 +vn -0.9063 -0.1939 0.3754 +vn -0.3583 0.9217 0.1484 +vn -0.8544 -0.3805 0.3539 +vn -0.5171 0.8286 0.2142 +vn -0.7699 -0.5528 0.3189 +vn -0.6561 0.7040 0.2717 +vn -0.6561 -0.7040 0.2717 +vn -0.7699 0.5528 0.3189 +vn -0.5171 -0.8286 0.2142 +vn -0.8544 0.3805 0.3539 +vn -0.3583 -0.9217 0.1484 +vn -0.9063 0.1939 0.3754 +vn -0.6965 0.7040 0.1385 +vn -0.8173 0.5528 0.1626 +vn -0.6965 -0.7040 0.1385 +vn -0.5490 -0.8286 0.1092 +vn -0.9070 0.3805 0.1804 +vn -0.3804 -0.9217 0.0757 +vn -0.9622 0.1939 0.1914 +vn -0.1971 -0.9796 0.0392 +vn -0.9808 0.0000 0.1951 +vn -0.1971 0.9796 0.0392 +vn -0.9622 -0.1939 0.1914 +vn -0.3804 0.9217 0.0757 +vn -0.9070 -0.3805 0.1804 +vn -0.5490 0.8286 0.1092 +vn -0.8173 -0.5528 0.1626 +vn -1.0000 0.0000 0.0000 +vn -0.9810 -0.1939 0.0000 +vn -0.2010 0.9796 0.0000 +vn -0.3879 0.9217 0.0000 +vn -0.9247 -0.3805 0.0000 +vn -0.5598 0.8286 0.0000 +vn -0.8333 -0.5528 0.0000 +vn -0.7101 0.7040 0.0000 +vn -0.7101 -0.7040 0.0000 +vn -0.8333 0.5528 0.0000 +vn -0.5598 -0.8286 0.0000 +vn -0.9247 0.3805 0.0000 +vn -0.3879 -0.9217 0.0000 +vn -0.9810 0.1939 0.0000 +vn -0.2010 -0.9796 0.0000 +vn -0.6965 -0.7040 -0.1385 +vn -0.5490 -0.8286 -0.1092 +vn -0.8173 0.5528 -0.1626 +vn -0.9070 0.3805 -0.1804 +vn -0.3804 -0.9217 -0.0757 +vn -0.9622 0.1939 -0.1914 +vn -0.1971 -0.9796 -0.0392 +vn -0.9808 0.0000 -0.1951 +vn -0.1971 0.9796 -0.0392 +vn -0.9622 -0.1939 -0.1914 +vn -0.3804 0.9217 -0.0757 +vn -0.9070 -0.3805 -0.1804 +vn -0.5490 0.8286 -0.1092 +vn -0.8173 -0.5528 -0.1626 +vn -0.6965 0.7040 -0.1385 +vn -0.1856 0.9796 -0.0769 +vn -0.3583 0.9217 -0.1484 +vn -0.9063 -0.1939 -0.3754 +vn -0.8544 -0.3805 -0.3539 +vn -0.5171 0.8286 -0.2142 +vn -0.7699 -0.5528 -0.3189 +vn -0.6561 0.7040 -0.2717 +vn -0.6561 -0.7040 -0.2717 +vn -0.7699 0.5528 -0.3189 +vn -0.5171 -0.8286 -0.2142 +vn -0.8544 0.3805 -0.3539 +vn -0.3583 -0.9217 -0.1484 +vn -0.9063 0.1939 -0.3754 +vn -0.1856 -0.9796 -0.0769 +vn -0.9239 0.0000 -0.3827 +vn -0.6929 0.5528 -0.4630 +vn -0.7689 0.3805 -0.5137 +vn -0.4654 -0.8286 -0.3110 +vn -0.3225 -0.9217 -0.2155 +vn -0.8157 0.1939 -0.5450 +vn -0.1671 -0.9796 -0.1116 +vn -0.8314 0.0000 -0.5556 +vn -0.1671 0.9796 -0.1116 +vn -0.8157 -0.1939 -0.5450 +vn -0.3225 0.9217 -0.2155 +vn -0.7689 -0.3805 -0.5137 +vn -0.4654 0.8286 -0.3110 +vn -0.6929 -0.5528 -0.4630 +vn -0.5904 0.7040 -0.3945 +vn -0.5904 -0.7040 -0.3945 +vn -0.6937 -0.1939 -0.6937 +vn -0.6539 -0.3805 -0.6539 +vn -0.2743 0.9217 -0.2743 +vn -0.3958 0.8286 -0.3958 +vn -0.5893 -0.5528 -0.5893 +vn -0.5021 0.7040 -0.5021 +vn -0.5021 -0.7040 -0.5021 +vn -0.5893 0.5528 -0.5893 +vn -0.3958 -0.8286 -0.3958 +vn -0.6539 0.3805 -0.6539 +vn -0.2743 -0.9217 -0.2743 +vn -0.6937 0.1939 -0.6937 +vn -0.1421 -0.9796 -0.1421 +vn -0.7071 0.0000 -0.7071 +vn -0.1421 0.9796 -0.1421 +vn -0.3110 -0.8286 -0.4654 +vn -0.2155 -0.9217 -0.3225 +vn -0.5137 0.3805 -0.7689 +vn -0.5450 0.1939 -0.8157 +vn -0.1116 -0.9796 -0.1671 +vn -0.5556 0.0000 -0.8314 +vn -0.1116 0.9796 -0.1671 +vn -0.5450 -0.1939 -0.8157 +vn -0.2155 0.9217 -0.3225 +vn -0.5137 -0.3805 -0.7689 +vn -0.3110 0.8286 -0.4654 +vn -0.4630 -0.5528 -0.6929 +vn -0.3945 0.7040 -0.5904 +vn -0.3945 -0.7040 -0.5904 +vn -0.4630 0.5528 -0.6929 +vn -0.3539 -0.3805 -0.8544 +vn -0.3189 -0.5528 -0.7699 +vn -0.2142 0.8286 -0.5171 +vn -0.2717 0.7040 -0.6561 +vn -0.2717 -0.7040 -0.6561 +vn -0.3189 0.5528 -0.7699 +vn -0.2142 -0.8286 -0.5171 +vn -0.3539 0.3805 -0.8544 +vn -0.1484 -0.9217 -0.3583 +vn -0.3754 0.1939 -0.9063 +vn -0.0769 -0.9796 -0.1856 +vn -0.3827 0.0000 -0.9239 +vn -0.0769 0.9796 -0.1856 +vn -0.3754 -0.1939 -0.9063 +vn -0.1484 0.9217 -0.3583 +vn -0.0757 -0.9217 -0.3804 +vn -0.0392 -0.9796 -0.1971 +vn -0.1914 0.1939 -0.9622 +vn -0.1951 0.0000 -0.9808 +vn -0.0392 0.9796 -0.1971 +vn -0.1914 -0.1939 -0.9622 +vn -0.0757 0.9217 -0.3804 +vn -0.1804 -0.3805 -0.9070 +vn -0.1092 0.8286 -0.5490 +vn -0.1626 -0.5528 -0.8173 +vn -0.1385 0.7040 -0.6965 +vn -0.1385 -0.7040 -0.6965 +vn -0.1626 0.5528 -0.8173 +vn -0.1092 -0.8286 -0.5490 +vn -0.1804 0.3805 -0.9070 +usemtl __tb_info_player_start +s 1 +f 479/1/1 478/2/2 20/3/3 21/4/4 +f 4/5/5 3/6/6 13/7/7 14/8/8 +f 480/9/9 479/1/1 21/4/4 22/10/10 +f 5/11/11 4/5/5 14/8/8 15/12/12 +f 10/13/13 480/9/9 22/10/10 23/14/14 +f 6/15/15 5/11/11 15/12/12 16/16/16 +f 481/17/17 10/13/13 23/14/14 24/18/18 +f 7/19/19 6/15/15 16/16/16 17/20/20 +f 482/21/21 481/17/17 24/18/18 25/22/22 +f 8/23/23 7/19/19 17/20/20 18/24/24 +f 1/25/25 297/26/26 11/27/27 +f 206/28/28 482/21/21 25/22/22 +f 9/29/29 8/30/23 18/31/24 19/32/30 +f 2/33/31 1/25/25 11/27/27 12/34/32 +f 478/2/2 9/29/29 19/32/30 20/3/3 +f 3/6/6 2/33/31 12/34/32 13/7/7 +f 20/3/3 19/32/30 34/35/33 35/36/34 +f 13/7/7 12/34/32 27/37/35 28/38/36 +f 21/4/4 20/3/3 35/36/34 36/39/37 +f 14/8/8 13/7/7 28/38/36 29/40/38 +f 22/10/10 21/4/4 36/39/37 37/41/39 +f 15/12/12 14/8/8 29/40/38 30/42/40 +f 23/14/14 22/10/10 37/41/39 38/43/41 +f 16/16/16 15/12/12 30/42/40 31/44/42 +f 24/18/18 23/14/14 38/43/41 39/45/43 +f 17/20/20 16/16/16 31/44/42 32/46/44 +f 25/22/22 24/18/18 39/45/43 40/47/45 +f 18/24/24 17/20/20 32/46/44 33/48/46 +f 11/27/27 297/26/26 26/49/47 +f 206/28/28 25/22/22 40/47/45 +f 19/32/30 18/31/24 33/50/46 34/35/33 +f 12/34/32 11/27/27 26/49/47 27/37/35 +f 39/45/43 38/43/41 53/51/48 54/52/49 +f 32/46/44 31/44/42 46/53/50 47/54/51 +f 40/47/45 39/45/43 54/52/49 55/55/52 +f 33/48/46 32/46/44 47/54/51 48/56/53 +f 26/49/47 297/26/26 41/57/54 +f 206/28/28 40/47/45 55/55/52 +f 34/35/33 33/50/46 48/58/53 49/59/55 +f 27/37/35 26/49/47 41/57/54 42/60/56 +f 35/36/34 34/35/33 49/59/55 50/61/57 +f 28/38/36 27/37/35 42/60/56 43/62/58 +f 36/39/37 35/36/34 50/61/57 51/63/59 +f 29/40/38 28/38/36 43/62/58 44/64/60 +f 37/41/39 36/39/37 51/63/59 52/65/61 +f 30/42/40 29/40/38 44/64/60 45/66/62 +f 38/43/41 37/41/39 52/65/61 53/51/48 +f 31/44/42 30/42/40 45/66/62 46/53/50 +f 43/62/58 42/60/56 57/67/63 58/68/64 +f 51/63/59 50/61/57 65/69/65 66/70/66 +f 44/64/60 43/62/58 58/68/64 59/71/67 +f 52/65/61 51/63/59 66/70/66 67/72/68 +f 45/66/62 44/64/60 59/71/67 60/73/69 +f 53/51/48 52/65/61 67/72/68 68/74/70 +f 46/53/50 45/66/62 60/73/69 61/75/71 +f 54/52/49 53/51/48 68/74/70 69/76/72 +f 47/54/51 46/53/50 61/75/71 62/77/73 +f 55/55/52 54/52/49 69/76/72 70/78/74 +f 48/56/53 47/54/51 62/77/73 63/79/75 +f 41/57/54 297/26/26 56/80/76 +f 206/28/28 55/55/52 70/78/74 +f 49/59/55 48/58/53 63/81/75 64/82/77 +f 42/60/56 41/57/54 56/80/76 57/67/63 +f 50/61/57 49/59/55 64/82/77 65/69/65 +f 62/77/73 61/75/71 76/83/78 77/84/79 +f 70/78/74 69/76/72 84/85/80 85/86/81 +f 63/79/75 62/77/73 77/84/79 78/87/82 +f 56/80/76 297/26/26 71/88/83 +f 206/28/28 70/78/74 85/86/81 +f 64/82/77 63/81/75 78/89/82 79/90/84 +f 57/67/63 56/80/76 71/88/83 72/91/85 +f 65/69/65 64/82/77 79/90/84 80/92/86 +f 58/68/64 57/67/63 72/91/85 73/93/87 +f 66/70/66 65/69/65 80/92/86 81/94/88 +f 59/71/67 58/68/64 73/93/87 74/95/89 +f 67/72/68 66/70/66 81/94/88 82/96/90 +f 60/73/69 59/71/67 74/95/89 75/97/91 +f 68/74/70 67/72/68 82/96/90 83/98/92 +f 61/75/71 60/73/69 75/97/91 76/83/78 +f 69/76/72 68/74/70 83/98/92 84/85/80 +f 81/94/88 80/92/86 95/99/93 96/100/94 +f 74/95/89 73/93/87 88/101/95 89/102/96 +f 82/96/90 81/94/88 96/100/94 97/103/97 +f 75/97/91 74/95/89 89/102/96 90/104/98 +f 83/98/92 82/96/90 97/103/97 98/105/99 +f 76/83/78 75/97/91 90/104/98 91/106/100 +f 84/85/80 83/98/92 98/105/99 99/107/101 +f 77/84/79 76/83/78 91/106/100 92/108/102 +f 85/86/81 84/85/80 99/107/101 100/109/103 +f 78/87/82 77/84/79 92/108/102 93/110/104 +f 71/88/83 297/26/26 86/111/105 +f 206/28/28 85/86/81 100/109/103 +f 79/90/84 78/89/82 93/112/104 94/113/106 +f 72/91/85 71/88/83 86/111/105 87/114/107 +f 80/92/86 79/90/84 94/113/106 95/99/93 +f 73/93/87 72/91/85 87/114/107 88/101/95 +f 100/109/103 99/107/101 114/115/108 115/116/109 +f 93/110/104 92/108/102 107/117/110 108/118/111 +f 86/111/105 297/26/26 101/119/112 +f 206/28/28 100/109/103 115/116/109 +f 94/113/106 93/112/104 108/120/111 109/121/113 +f 87/114/107 86/111/105 101/119/112 102/122/114 +f 95/99/93 94/113/106 109/121/113 110/123/115 +f 88/101/95 87/114/107 102/122/114 103/124/116 +f 96/100/94 95/99/93 110/123/115 111/125/117 +f 89/102/96 88/101/95 103/124/116 104/126/118 +f 97/103/97 96/100/94 111/125/117 112/127/119 +f 90/104/98 89/102/96 104/126/118 105/128/120 +f 98/105/99 97/103/97 112/127/119 113/129/121 +f 91/106/100 90/104/98 105/128/120 106/130/122 +f 99/107/101 98/105/99 113/129/121 114/115/108 +f 92/108/102 91/106/100 106/130/122 107/117/110 +f 104/126/118 103/124/116 118/131/123 119/132/124 +f 112/127/119 111/125/117 126/133/125 127/134/126 +f 105/128/120 104/126/118 119/132/124 120/135/127 +f 113/129/121 112/127/119 127/134/126 128/136/128 +f 106/130/122 105/128/120 120/135/127 121/137/129 +f 114/115/108 113/129/121 128/136/128 129/138/130 +f 107/117/110 106/130/122 121/137/129 122/139/131 +f 115/116/109 114/115/108 129/138/130 130/140/132 +f 108/118/111 107/117/110 122/139/131 123/141/133 +f 101/119/112 297/26/26 116/142/134 +f 206/28/28 115/116/109 130/140/132 +f 109/121/113 108/120/111 123/143/133 124/144/135 +f 102/122/114 101/119/112 116/142/134 117/145/136 +f 110/123/115 109/121/113 124/144/135 125/146/137 +f 103/124/116 102/122/114 117/145/136 118/131/123 +f 111/125/117 110/123/115 125/146/137 126/133/125 +f 123/147/133 122/148/131 137/149/138 138/150/139 +f 116/151/134 297/152/26 131/153/140 +f 206/154/28 130/155/132 145/156/141 +f 124/157/135 123/158/133 138/159/139 139/160/142 +f 117/161/136 116/151/134 131/153/140 132/162/143 +f 125/163/137 124/157/135 139/160/142 140/164/144 +f 118/165/123 117/161/136 132/162/143 133/166/145 +f 126/167/125 125/163/137 140/164/144 141/168/146 +f 119/169/124 118/165/123 133/166/145 134/170/147 +f 127/171/126 126/167/125 141/168/146 142/172/148 +f 120/173/127 119/169/124 134/170/147 135/174/149 +f 128/175/128 127/171/126 142/172/148 143/176/150 +f 121/177/129 120/173/127 135/174/149 136/178/151 +f 129/179/130 128/175/128 143/176/150 144/180/152 +f 122/148/131 121/177/129 136/178/151 137/149/138 +f 130/155/132 129/179/130 144/180/152 145/156/141 +f 142/172/148 141/168/146 156/181/153 157/182/154 +f 135/174/149 134/170/147 149/183/155 150/184/156 +f 143/176/150 142/172/148 157/182/154 158/185/157 +f 136/178/151 135/174/149 150/184/156 151/186/158 +f 144/180/152 143/176/150 158/185/157 159/187/159 +f 137/149/138 136/178/151 151/186/158 152/188/160 +f 145/156/141 144/180/152 159/187/159 160/189/161 +f 138/150/139 137/149/138 152/188/160 153/190/162 +f 131/153/140 297/152/26 146/191/163 +f 206/154/28 145/156/141 160/189/161 +f 139/160/142 138/159/139 153/192/162 154/193/164 +f 132/162/143 131/153/140 146/191/163 147/194/165 +f 140/164/144 139/160/142 154/193/164 155/195/166 +f 133/166/145 132/162/143 147/194/165 148/196/167 +f 141/168/146 140/164/144 155/195/166 156/181/153 +f 134/170/147 133/166/145 148/196/167 149/183/155 +f 206/154/28 160/189/161 175/197/168 +f 154/193/164 153/192/162 168/198/169 169/199/170 +f 147/194/165 146/191/163 161/200/171 162/201/172 +f 155/195/166 154/193/164 169/199/170 170/202/173 +f 148/196/167 147/194/165 162/201/172 163/203/174 +f 156/181/153 155/195/166 170/202/173 171/204/175 +f 149/183/155 148/196/167 163/203/174 164/205/176 +f 157/182/154 156/181/153 171/204/175 172/206/177 +f 150/184/156 149/183/155 164/205/176 165/207/178 +f 158/185/157 157/182/154 172/206/177 173/208/179 +f 151/186/158 150/184/156 165/207/178 166/209/180 +f 159/187/159 158/185/157 173/208/179 174/210/181 +f 152/188/160 151/186/158 166/209/180 167/211/182 +f 160/189/161 159/187/159 174/210/181 175/197/168 +f 153/190/162 152/188/160 167/211/182 168/212/169 +f 146/191/163 297/152/26 161/200/171 +f 173/208/179 172/206/177 187/213/183 188/214/184 +f 166/209/180 165/207/178 180/215/185 181/216/186 +f 174/210/181 173/208/179 188/214/184 189/217/187 +f 167/211/182 166/209/180 181/216/186 182/218/188 +f 175/197/168 174/210/181 189/217/187 190/219/189 +f 168/212/169 167/211/182 182/218/188 183/220/190 +f 161/200/171 297/152/26 176/221/191 +f 206/154/28 175/197/168 190/219/189 +f 169/199/170 168/198/169 183/222/190 184/223/192 +f 162/201/172 161/200/171 176/221/191 177/224/193 +f 170/202/173 169/199/170 184/223/192 185/225/194 +f 163/203/174 162/201/172 177/224/193 178/226/195 +f 171/204/175 170/202/173 185/225/194 186/227/196 +f 164/205/176 163/203/174 178/226/195 179/228/197 +f 172/206/177 171/204/175 186/227/196 187/213/183 +f 165/207/178 164/205/176 179/228/197 180/215/185 +f 177/224/193 176/221/191 191/229/198 192/230/199 +f 185/225/194 184/223/192 199/231/200 200/232/201 +f 178/226/195 177/224/193 192/230/199 193/233/202 +f 186/227/196 185/225/194 200/232/201 201/234/203 +f 179/228/197 178/226/195 193/233/202 194/235/204 +f 187/213/183 186/227/196 201/234/203 202/236/205 +f 180/215/185 179/228/197 194/235/204 195/237/206 +f 188/214/184 187/213/183 202/236/205 203/238/207 +f 181/216/186 180/215/185 195/237/206 196/239/208 +f 189/217/187 188/214/184 203/238/207 204/240/209 +f 182/218/188 181/216/186 196/239/208 197/241/210 +f 190/219/189 189/217/187 204/240/209 205/242/211 +f 183/220/190 182/218/188 197/241/210 198/243/212 +f 176/221/191 297/152/26 191/229/198 +f 206/154/28 190/219/189 205/242/211 +f 184/223/192 183/222/190 198/244/212 199/231/200 +f 196/239/208 195/237/206 211/245/213 212/246/214 +f 204/240/209 203/238/207 219/247/215 220/248/216 +f 197/241/210 196/239/208 212/246/214 213/249/217 +f 205/242/211 204/240/209 220/248/216 221/250/218 +f 198/243/212 197/241/210 213/249/217 214/251/219 +f 191/229/198 297/152/26 207/252/220 +f 206/154/28 205/242/211 221/250/218 +f 199/231/200 198/244/212 214/253/219 215/254/221 +f 192/230/199 191/229/198 207/252/220 208/255/222 +f 200/232/201 199/231/200 215/254/221 216/256/223 +f 193/233/202 192/230/199 208/255/222 209/257/224 +f 201/234/203 200/232/201 216/256/223 217/258/225 +f 194/235/204 193/233/202 209/257/224 210/259/226 +f 202/236/205 201/234/203 217/258/225 218/260/227 +f 195/237/206 194/235/204 210/259/226 211/245/213 +f 203/238/207 202/236/205 218/260/227 219/247/215 +f 216/256/223 215/254/221 230/261/228 231/262/229 +f 209/257/224 208/255/222 223/263/230 224/264/231 +f 217/258/225 216/256/223 231/262/229 232/265/232 +f 210/259/226 209/257/224 224/264/231 225/266/233 +f 218/260/227 217/258/225 232/265/232 233/267/234 +f 211/245/213 210/259/226 225/266/233 226/268/235 +f 219/247/215 218/260/227 233/267/234 234/269/236 +f 212/246/214 211/245/213 226/268/235 227/270/237 +f 220/248/216 219/247/215 234/269/236 235/271/238 +f 213/249/217 212/246/214 227/270/237 228/272/239 +f 221/250/218 220/248/216 235/271/238 236/273/240 +f 214/251/219 213/249/217 228/272/239 229/274/241 +f 207/252/220 297/152/26 222/275/242 +f 206/154/28 221/250/218 236/273/240 +f 215/254/221 214/253/219 229/276/241 230/261/228 +f 208/255/222 207/252/220 222/275/242 223/263/230 +f 235/271/238 234/269/236 249/277/243 250/278/244 +f 228/272/239 227/270/237 242/279/245 243/280/246 +f 236/273/240 235/271/238 250/278/244 251/281/247 +f 229/274/241 228/272/239 243/280/246 244/282/248 +f 222/275/242 297/152/26 237/283/249 +f 206/154/28 236/273/240 251/281/247 +f 230/261/228 229/276/241 244/284/248 245/285/250 +f 223/263/230 222/275/242 237/283/249 238/286/251 +f 231/262/229 230/261/228 245/285/250 246/287/252 +f 224/264/231 223/263/230 238/286/251 239/288/253 +f 232/265/232 231/262/229 246/287/252 247/289/254 +f 225/266/233 224/264/231 239/288/253 240/290/255 +f 233/267/234 232/265/232 247/289/254 248/291/256 +f 226/268/235 225/266/233 240/290/255 241/292/257 +f 234/269/236 233/267/234 248/291/256 249/277/243 +f 227/270/237 226/268/235 241/292/257 242/279/245 +f 239/293/253 238/294/251 253/295/258 254/296/259 +f 247/297/254 246/298/252 261/299/260 262/300/261 +f 240/301/255 239/293/253 254/296/259 255/302/262 +f 248/303/256 247/297/254 262/300/261 263/304/263 +f 241/305/257 240/301/255 255/302/262 256/306/264 +f 249/307/243 248/303/256 263/304/263 264/308/265 +f 242/309/245 241/305/257 256/306/264 257/310/266 +f 250/311/244 249/307/243 264/308/265 265/312/267 +f 243/313/246 242/309/245 257/310/266 258/314/268 +f 251/315/247 250/311/244 265/312/267 266/316/269 +f 244/317/248 243/313/246 258/314/268 259/318/270 +f 237/319/249 297/320/26 252/321/271 +f 206/322/28 251/315/247 266/316/269 +f 245/323/250 244/324/248 259/325/270 260/326/272 +f 238/294/251 237/319/249 252/321/271 253/295/258 +f 246/298/252 245/323/250 260/326/272 261/299/260 +f 258/314/268 257/310/266 272/327/273 273/328/274 +f 266/316/269 265/312/267 280/329/275 281/330/276 +f 259/318/270 258/314/268 273/328/274 274/331/277 +f 252/321/271 297/320/26 267/332/278 +f 206/322/28 266/316/269 281/330/276 +f 260/326/272 259/325/270 274/333/277 275/334/279 +f 253/295/258 252/321/271 267/332/278 268/335/280 +f 261/299/260 260/326/272 275/334/279 276/336/281 +f 254/296/259 253/295/258 268/335/280 269/337/282 +f 262/300/261 261/299/260 276/336/281 277/338/283 +f 255/302/262 254/296/259 269/337/282 270/339/284 +f 263/304/263 262/300/261 277/338/283 278/340/285 +f 256/306/264 255/302/262 270/339/284 271/341/286 +f 264/308/265 263/304/263 278/340/285 279/342/287 +f 257/310/266 256/306/264 271/341/286 272/327/273 +f 265/312/267 264/308/265 279/342/287 280/329/275 +f 277/338/283 276/336/281 291/343/288 292/344/289 +f 270/339/284 269/337/282 284/345/290 285/346/291 +f 278/340/285 277/338/283 292/344/289 293/347/292 +f 271/341/286 270/339/284 285/346/291 286/348/293 +f 279/342/287 278/340/285 293/347/292 294/349/294 +f 272/327/273 271/341/286 286/348/293 287/350/295 +f 280/329/275 279/342/287 294/349/294 295/351/296 +f 273/328/274 272/327/273 287/350/295 288/352/297 +f 281/330/276 280/329/275 295/351/296 296/353/298 +f 274/331/277 273/328/274 288/352/297 289/354/299 +f 267/332/278 297/320/26 282/355/300 +f 206/322/28 281/330/276 296/353/298 +f 275/334/279 274/333/277 289/356/299 290/357/301 +f 268/335/280 267/332/278 282/355/300 283/358/302 +f 276/336/281 275/334/279 290/357/301 291/343/288 +f 269/337/282 268/335/280 283/358/302 284/345/290 +f 296/353/298 295/351/296 311/359/303 312/360/304 +f 289/354/299 288/352/297 304/361/305 305/362/306 +f 282/355/300 297/320/26 298/363/307 +f 206/322/28 296/353/298 312/360/304 +f 290/357/301 289/356/299 305/364/306 306/365/308 +f 283/358/302 282/355/300 298/363/307 299/366/309 +f 291/343/288 290/357/301 306/365/308 307/367/310 +f 284/345/290 283/358/302 299/366/309 300/368/311 +f 292/344/289 291/343/288 307/367/310 308/369/312 +f 285/346/291 284/345/290 300/368/311 301/370/313 +f 293/347/292 292/344/289 308/369/312 309/371/314 +f 286/348/293 285/346/291 301/370/313 302/372/315 +f 294/349/294 293/347/292 309/371/314 310/373/316 +f 287/350/295 286/348/293 302/372/315 303/374/317 +f 295/351/296 294/349/294 310/373/316 311/359/303 +f 288/352/297 287/350/295 303/374/317 304/361/305 +f 309/371/314 308/369/312 323/375/318 324/376/319 +f 302/372/315 301/370/313 316/377/320 317/378/321 +f 310/373/316 309/371/314 324/376/319 325/379/322 +f 303/374/317 302/372/315 317/378/321 318/380/323 +f 311/359/303 310/373/316 325/379/322 326/381/324 +f 304/361/305 303/374/317 318/380/323 319/382/325 +f 312/360/304 311/359/303 326/381/324 327/383/326 +f 305/362/306 304/361/305 319/382/325 320/384/327 +f 298/363/307 297/320/26 313/385/328 +f 206/322/28 312/360/304 327/383/326 +f 306/365/308 305/364/306 320/386/327 321/387/329 +f 299/366/309 298/363/307 313/385/328 314/388/330 +f 307/367/310 306/365/308 321/387/329 322/389/331 +f 300/368/311 299/366/309 314/388/330 315/390/332 +f 308/369/312 307/367/310 322/389/331 323/375/318 +f 301/370/313 300/368/311 315/390/332 316/377/320 +f 313/385/328 297/320/26 328/391/333 +f 206/322/28 327/383/326 342/392/334 +f 321/387/329 320/386/327 335/393/335 336/394/336 +f 314/388/330 313/385/328 328/391/333 329/395/337 +f 322/389/331 321/387/329 336/394/336 337/396/338 +f 315/390/332 314/388/330 329/395/337 330/397/339 +f 323/375/318 322/389/331 337/396/338 338/398/340 +f 316/377/320 315/390/332 330/397/339 331/399/341 +f 324/376/319 323/375/318 338/398/340 339/400/342 +f 317/378/321 316/377/320 331/399/341 332/401/343 +f 325/379/322 324/376/319 339/400/342 340/402/344 +f 318/380/323 317/378/321 332/401/343 333/403/345 +f 326/381/324 325/379/322 340/402/344 341/404/346 +f 319/382/325 318/380/323 333/403/345 334/405/347 +f 327/383/326 326/381/324 341/404/346 342/392/334 +f 320/384/327 319/382/325 334/405/347 335/406/335 +f 332/401/343 331/399/341 346/407/348 347/408/349 +f 340/402/344 339/400/342 354/409/350 355/410/351 +f 333/403/345 332/401/343 347/408/349 348/411/352 +f 341/404/346 340/402/344 355/410/351 356/412/353 +f 334/405/347 333/403/345 348/411/352 349/413/354 +f 342/392/334 341/404/346 356/412/353 357/414/355 +f 335/406/335 334/405/347 349/413/354 350/415/356 +f 328/391/333 297/320/26 343/416/357 +f 206/322/28 342/392/334 357/414/355 +f 336/394/336 335/393/335 350/417/356 351/418/358 +f 329/395/337 328/391/333 343/416/357 344/419/359 +f 337/396/338 336/394/336 351/418/358 352/420/360 +f 330/397/339 329/395/337 344/419/359 345/421/361 +f 338/398/340 337/396/338 352/420/360 353/422/362 +f 331/399/341 330/397/339 345/421/361 346/407/348 +f 339/400/342 338/398/340 353/422/362 354/409/350 +f 351/418/358 350/417/356 365/423/363 366/424/364 +f 344/419/359 343/416/357 358/425/365 359/426/366 +f 352/420/360 351/418/358 366/424/364 367/427/367 +f 345/421/361 344/419/359 359/426/366 360/428/368 +f 353/422/362 352/420/360 367/427/367 368/429/369 +f 346/407/348 345/421/361 360/428/368 361/430/370 +f 354/409/350 353/422/362 368/429/369 369/431/371 +f 347/408/349 346/407/348 361/430/370 362/432/372 +f 355/410/351 354/409/350 369/431/371 370/433/373 +f 348/411/352 347/408/349 362/432/372 363/434/374 +f 356/412/353 355/410/351 370/433/373 371/435/375 +f 349/413/354 348/411/352 363/434/374 364/436/376 +f 357/414/355 356/412/353 371/435/375 372/437/377 +f 350/415/356 349/413/354 364/436/376 365/438/363 +f 343/416/357 297/320/26 358/425/365 +f 206/322/28 357/414/355 372/437/377 +f 370/439/373 369/440/371 384/441/378 385/442/379 +f 363/443/374 362/444/372 377/445/380 378/446/381 +f 371/447/375 370/439/373 385/442/379 386/448/382 +f 364/449/376 363/443/374 378/446/381 379/450/383 +f 372/451/377 371/447/375 386/448/382 387/452/384 +f 365/453/363 364/449/376 379/450/383 380/454/385 +f 358/455/365 297/456/26 373/457/386 +f 206/458/28 372/451/377 387/452/384 +f 366/459/364 365/460/363 380/461/385 381/462/387 +f 359/463/366 358/455/365 373/457/386 374/464/388 +f 367/465/367 366/459/364 381/462/387 382/466/389 +f 360/467/368 359/463/366 374/464/388 375/468/390 +f 368/469/369 367/465/367 382/466/389 383/470/391 +f 361/471/370 360/467/368 375/468/390 376/472/392 +f 369/440/371 368/469/369 383/470/391 384/441/378 +f 362/444/372 361/471/370 376/472/392 377/445/380 +f 374/464/388 373/457/386 388/473/393 389/474/394 +f 382/466/389 381/462/387 396/475/395 397/476/396 +f 375/468/390 374/464/388 389/474/394 390/477/397 +f 383/470/391 382/466/389 397/476/396 398/478/398 +f 376/472/392 375/468/390 390/477/397 391/479/399 +f 384/441/378 383/470/391 398/478/398 399/480/400 +f 377/445/380 376/472/392 391/479/399 392/481/401 +f 385/442/379 384/441/378 399/480/400 400/482/402 +f 378/446/381 377/445/380 392/481/401 393/483/403 +f 386/448/382 385/442/379 400/482/402 401/484/404 +f 379/450/383 378/446/381 393/483/403 394/485/405 +f 387/452/384 386/448/382 401/484/404 402/486/406 +f 380/454/385 379/450/383 394/485/405 395/487/407 +f 373/457/386 297/456/26 388/473/393 +f 206/458/28 387/452/384 402/486/406 +f 381/462/387 380/461/385 395/488/407 396/475/395 +f 393/483/403 392/481/401 407/489/408 408/490/409 +f 401/484/404 400/482/402 415/491/410 416/492/411 +f 394/485/405 393/483/403 408/490/409 409/493/412 +f 402/486/406 401/484/404 416/492/411 417/494/413 +f 395/487/407 394/485/405 409/493/412 410/495/414 +f 388/473/393 297/456/26 403/496/415 +f 206/458/28 402/486/406 417/494/413 +f 396/475/395 395/488/407 410/497/414 411/498/416 +f 389/474/394 388/473/393 403/496/415 404/499/417 +f 397/476/396 396/475/395 411/498/416 412/500/418 +f 390/477/397 389/474/394 404/499/417 405/501/419 +f 398/478/398 397/476/396 412/500/418 413/502/420 +f 391/479/399 390/477/397 405/501/419 406/503/421 +f 399/480/400 398/478/398 413/502/420 414/504/422 +f 392/481/401 391/479/399 406/503/421 407/489/408 +f 400/482/402 399/480/400 414/504/422 415/491/410 +f 412/500/418 411/498/416 426/505/423 427/506/424 +f 405/501/419 404/499/417 419/507/425 420/508/426 +f 413/502/420 412/500/418 427/506/424 428/509/427 +f 406/503/421 405/501/419 420/508/426 421/510/428 +f 414/504/422 413/502/420 428/509/427 429/511/429 +f 407/489/408 406/503/421 421/510/428 422/512/430 +f 415/491/410 414/504/422 429/511/429 430/513/431 +f 408/490/409 407/489/408 422/512/430 423/514/432 +f 416/492/411 415/491/410 430/513/431 431/515/433 +f 409/493/412 408/490/409 423/514/432 424/516/434 +f 417/494/413 416/492/411 431/515/433 432/517/435 +f 410/495/414 409/493/412 424/516/434 425/518/436 +f 403/496/415 297/456/26 418/519/437 +f 206/458/28 417/494/413 432/517/435 +f 411/498/416 410/497/414 425/520/436 426/505/423 +f 404/499/417 403/496/415 418/519/437 419/507/425 +f 431/515/433 430/513/431 445/521/438 446/522/439 +f 424/516/434 423/514/432 438/523/440 439/524/441 +f 432/517/435 431/515/433 446/522/439 447/525/442 +f 425/518/436 424/516/434 439/524/441 440/526/443 +f 418/519/437 297/456/26 433/527/444 +f 206/458/28 432/517/435 447/525/442 +f 426/505/423 425/520/436 440/528/443 441/529/445 +f 419/507/425 418/519/437 433/527/444 434/530/446 +f 427/506/424 426/505/423 441/529/445 442/531/447 +f 420/508/426 419/507/425 434/530/446 435/532/448 +f 428/509/427 427/506/424 442/531/447 443/533/449 +f 421/510/428 420/508/426 435/532/448 436/534/450 +f 429/511/429 428/509/427 443/533/449 444/535/451 +f 422/512/430 421/510/428 436/534/450 437/536/452 +f 430/513/431 429/511/429 444/535/451 445/521/438 +f 423/514/432 422/512/430 437/536/452 438/523/440 +f 443/533/449 442/531/447 457/537/453 458/538/454 +f 436/534/450 435/532/448 450/539/455 451/540/456 +f 444/535/451 443/533/449 458/538/454 459/541/457 +f 437/536/452 436/534/450 451/540/456 452/542/458 +f 445/521/438 444/535/451 459/541/457 460/543/459 +f 438/523/440 437/536/452 452/542/458 453/544/460 +f 446/522/439 445/521/438 460/543/459 461/545/461 +f 439/524/441 438/523/440 453/544/460 454/546/462 +f 447/525/442 446/522/439 461/545/461 462/547/463 +f 440/526/443 439/524/441 454/546/462 455/548/464 +f 433/527/444 297/456/26 448/549/465 +f 206/458/28 447/525/442 462/547/463 +f 441/529/445 440/528/443 455/550/464 456/551/466 +f 434/530/446 433/527/444 448/549/465 449/552/467 +f 442/531/447 441/529/445 456/551/466 457/537/453 +f 435/532/448 434/530/446 449/552/467 450/539/455 +f 462/547/463 461/545/461 476/553/468 477/554/469 +f 455/548/464 454/546/462 469/555/470 470/556/471 +f 448/549/465 297/456/26 463/557/472 +f 206/458/28 462/547/463 477/554/469 +f 456/551/466 455/550/464 470/558/471 471/559/473 +f 449/552/467 448/549/465 463/557/472 464/560/474 +f 457/537/453 456/551/466 471/559/473 472/561/475 +f 450/539/455 449/552/467 464/560/474 465/562/476 +f 458/538/454 457/537/453 472/561/475 473/563/477 +f 451/540/456 450/539/455 465/562/476 466/564/478 +f 459/541/457 458/538/454 473/563/477 474/565/479 +f 452/542/458 451/540/456 466/564/478 467/566/480 +f 460/543/459 459/541/457 474/565/479 475/567/481 +f 453/544/460 452/542/458 467/566/480 468/568/482 +f 461/545/461 460/543/459 475/567/481 476/553/468 +f 454/546/462 453/544/460 468/568/482 469/555/470 +f 466/564/478 465/562/476 3/569/6 4/570/5 +f 474/565/479 473/563/477 479/571/1 480/572/9 +f 467/566/480 466/564/478 4/570/5 5/573/11 +f 475/567/481 474/565/479 480/572/9 10/574/13 +f 468/568/482 467/566/480 5/573/11 6/575/15 +f 476/553/468 475/567/481 10/574/13 481/576/17 +f 469/555/470 468/568/482 6/575/15 7/577/19 +f 477/554/469 476/553/468 481/576/17 482/578/21 +f 470/556/471 469/555/470 7/577/19 8/579/23 +f 463/557/472 297/456/26 1/580/25 +f 206/458/28 477/554/469 482/578/21 +f 471/559/473 470/558/471 8/581/23 9/582/29 +f 464/560/474 463/557/472 1/580/25 2/583/31 +f 472/561/475 471/559/473 9/582/29 478/584/2 +f 465/562/476 464/560/474 2/583/31 3/569/6 +f 473/563/477 472/561/475 478/584/2 479/571/1 diff --git a/tools/trenchbroom/games/Neverball/assets/__tb_light_1.obj b/tools/trenchbroom/games/Neverball/assets/__tb_light_1.obj new file mode 100644 index 0000000..2ce542c --- /dev/null +++ b/tools/trenchbroom/games/Neverball/assets/__tb_light_1.obj @@ -0,0 +1,232 @@ +# Blender v2.79 (sub 0) OBJ File: '__tb_info_player_start.blend' +# www.blender.org +mtllib __tb_light_1.mtl +o Circle +v -0.000000 0.125000 -0.012500 +v 0.024386 0.122598 -0.012500 +v 0.047835 0.115485 -0.012500 +v 0.069446 0.103934 -0.012500 +v 0.088388 0.088388 -0.012500 +v 0.103934 0.069446 -0.012500 +v 0.115485 0.047835 -0.012500 +v 0.122598 0.024386 -0.012500 +v 0.125000 -0.000000 -0.012500 +v 0.122598 -0.024386 -0.012500 +v 0.115485 -0.047835 -0.012500 +v 0.103934 -0.069446 -0.012500 +v 0.088388 -0.088388 -0.012500 +v 0.069446 -0.103934 -0.012500 +v 0.047835 -0.115485 -0.012500 +v 0.024386 -0.122598 -0.012500 +v -0.000000 -0.125000 -0.012500 +v -0.024386 -0.122598 -0.012500 +v -0.047835 -0.115485 -0.012500 +v -0.069446 -0.103934 -0.012500 +v -0.088388 -0.088388 -0.012500 +v -0.103934 -0.069446 -0.012500 +v -0.115485 -0.047835 -0.012500 +v -0.122598 -0.024386 -0.012500 +v -0.125000 0.000000 -0.012500 +v -0.122598 0.024386 -0.012500 +v -0.115485 0.047836 -0.012500 +v -0.103934 0.069446 -0.012500 +v -0.088388 0.088388 -0.012500 +v -0.069446 0.103934 -0.012500 +v -0.047835 0.115485 -0.012500 +v -0.024386 0.122598 -0.012500 +v -0.000000 0.125000 0.012500 +v 0.024386 0.122598 0.012500 +v 0.047835 0.115485 0.012500 +v 0.069446 0.103934 0.012500 +v 0.088388 0.088388 0.012500 +v 0.103934 0.069446 0.012500 +v 0.115485 0.047835 0.012500 +v 0.122598 0.024386 0.012500 +v 0.125000 -0.000000 0.012500 +v 0.122598 -0.024386 0.012500 +v 0.115485 -0.047835 0.012500 +v 0.103934 -0.069446 0.012500 +v 0.088388 -0.088388 0.012500 +v 0.069446 -0.103934 0.012500 +v 0.047835 -0.115485 0.012500 +v 0.024386 -0.122598 0.012500 +v -0.000000 -0.125000 0.012500 +v -0.024386 -0.122598 0.012500 +v -0.047835 -0.115485 0.012500 +v -0.069446 -0.103934 0.012500 +v -0.088388 -0.088388 0.012500 +v -0.103934 -0.069446 0.012500 +v -0.115485 -0.047835 0.012500 +v -0.122598 -0.024386 0.012500 +v -0.125000 0.000000 0.012500 +v -0.122598 0.024386 0.012500 +v -0.115485 0.047836 0.012500 +v -0.103934 0.069446 0.012500 +v -0.088388 0.088388 0.012500 +v -0.069446 0.103934 0.012500 +v -0.047835 0.115485 0.012500 +v -0.024386 0.122598 0.012500 +vt 0.500000 1.000000 +vt 0.402455 0.990393 +vt 0.308658 0.961940 +vt 0.222215 0.915735 +vt 0.146447 0.853553 +vt 0.084265 0.777785 +vt 0.038060 0.691342 +vt 0.009607 0.597545 +vt 0.000000 0.500000 +vt 0.009607 0.402455 +vt 0.038060 0.308658 +vt 0.084265 0.222215 +vt 0.146447 0.146447 +vt 0.222215 0.084265 +vt 0.308658 0.038060 +vt 0.402455 0.009607 +vt 0.500000 0.000000 +vt 0.597545 0.009607 +vt 0.691342 0.038060 +vt 0.777785 0.084265 +vt 0.853554 0.146447 +vt 0.915735 0.222215 +vt 0.961940 0.308659 +vt 0.990393 0.402455 +vt 1.000000 0.500000 +vt 0.990393 0.597546 +vt 0.961940 0.691342 +vt 0.915734 0.777786 +vt 0.853553 0.853554 +vt 0.777785 0.915735 +vt 0.691341 0.961940 +vt 0.597544 0.990393 +vt 0.500000 1.000000 +vt 0.402456 0.990393 +vt 0.308659 0.961940 +vt 0.222215 0.915735 +vt 0.146447 0.853554 +vt 0.084266 0.777786 +vt 0.038060 0.691342 +vt 0.009607 0.597546 +vt 0.000000 0.500000 +vt 0.009607 0.402455 +vt 0.038060 0.308659 +vt 0.084265 0.222215 +vt 0.146446 0.146447 +vt 0.222215 0.084265 +vt 0.308658 0.038060 +vt 0.402455 0.009607 +vt 0.500000 0.000000 +vt 0.597545 0.009607 +vt 0.691342 0.038060 +vt 0.777785 0.084265 +vt 0.853553 0.146447 +vt 0.915735 0.222215 +vt 0.961940 0.308658 +vt 0.990393 0.402455 +vt 1.000000 0.500000 +vt 0.990393 0.597545 +vt 0.961940 0.691342 +vt 0.915735 0.777785 +vt 0.853553 0.853553 +vt 0.777785 0.915735 +vt 0.691342 0.961940 +vt 0.597545 0.990393 +vt 0.146447 0.146447 +vt 0.222215 0.084265 +vt 0.961940 0.691342 +vt 0.915734 0.777786 +vt 0.308658 0.038060 +vt 0.402455 0.990393 +vt 0.853553 0.853554 +vt 0.402455 0.009607 +vt 0.308658 0.961940 +vt 0.777785 0.915735 +vt 0.222215 0.915735 +vt 0.691341 0.961940 +vt 0.597545 0.009607 +vt 0.146447 0.853553 +vt 0.597544 0.990393 +vt 0.691342 0.038060 +vt 0.084265 0.777785 +vt 0.777785 0.084265 +vt 0.038060 0.691342 +vt 0.853554 0.146447 +vt 0.009607 0.597545 +vt 0.915735 0.222215 +vt 0.000000 0.500000 +vt 0.961940 0.308659 +vt 0.009607 0.402455 +vt 0.990393 0.402455 +vt 0.038060 0.308658 +vt 1.000000 0.500000 +vt 0.084265 0.222215 +vt 0.990393 0.597546 +vn 0.0000 -0.0000 -1.0000 +vn -0.0000 0.0000 1.0000 +vn 0.6344 -0.7730 0.0000 +vn -0.8819 0.4714 0.0000 +vn 0.4714 -0.8819 0.0000 +vn 0.0980 0.9952 0.0000 +vn -0.7730 0.6344 0.0000 +vn 0.2903 -0.9569 -0.0000 +vn 0.2903 0.9569 0.0000 +vn -0.6344 0.7730 0.0000 +vn 0.0980 -0.9952 0.0000 +vn 0.4714 0.8819 0.0000 +vn -0.4714 0.8819 0.0000 +vn -0.0980 -0.9952 -0.0000 +vn 0.6344 0.7730 0.0000 +vn -0.2903 0.9569 0.0000 +vn -0.2903 -0.9569 0.0000 +vn 0.7730 0.6344 0.0000 +vn -0.0980 0.9952 0.0000 +vn -0.4714 -0.8819 0.0000 +vn 0.8819 0.4714 0.0000 +vn -0.6344 -0.7730 0.0000 +vn 0.9569 0.2903 0.0000 +vn -0.7730 -0.6344 0.0000 +vn 0.9952 0.0980 0.0000 +vn -0.8819 -0.4714 0.0000 +vn 0.9952 -0.0980 0.0000 +vn -0.9569 -0.2903 0.0000 +vn 0.9569 -0.2903 0.0000 +vn -0.9952 -0.0980 0.0000 +vn 0.8819 -0.4714 0.0000 +vn -0.9952 0.0980 0.0000 +vn 0.7730 -0.6344 0.0000 +vn -0.9569 0.2903 0.0000 +usemtl mtrl/yellow +s off +f 1/1/1 2/2/1 3/3/1 4/4/1 5/5/1 6/6/1 7/7/1 8/8/1 9/9/1 10/10/1 11/11/1 12/12/1 13/13/1 14/14/1 15/15/1 16/16/1 17/17/1 18/18/1 19/19/1 20/20/1 21/21/1 22/22/1 23/23/1 24/24/1 25/25/1 26/26/1 27/27/1 28/28/1 29/29/1 30/30/1 31/31/1 32/32/1 +f 33/33/2 64/34/2 63/35/2 62/36/2 61/37/2 60/38/2 59/39/2 58/40/2 57/41/2 56/42/2 55/43/2 54/44/2 53/45/2 52/46/2 51/47/2 50/48/2 49/49/2 48/50/2 47/51/2 46/52/2 45/53/2 44/54/2 43/55/2 42/56/2 41/57/2 40/58/2 39/59/2 38/60/2 37/61/2 36/62/2 35/63/2 34/64/2 +f 13/13/3 45/65/3 46/66/3 14/14/3 +f 27/27/4 59/67/4 60/68/4 28/28/4 +f 14/14/5 46/66/5 47/69/5 15/15/5 +f 1/1/6 33/33/6 34/70/6 2/2/6 +f 28/28/7 60/68/7 61/71/7 29/29/7 +f 15/15/8 47/69/8 48/72/8 16/16/8 +f 2/2/9 34/70/9 35/73/9 3/3/9 +f 29/29/10 61/71/10 62/74/10 30/30/10 +f 16/16/11 48/72/11 49/49/11 17/17/11 +f 3/3/12 35/73/12 36/75/12 4/4/12 +f 30/30/13 62/74/13 63/76/13 31/31/13 +f 17/17/14 49/49/14 50/77/14 18/18/14 +f 4/4/15 36/75/15 37/78/15 5/5/15 +f 31/31/16 63/76/16 64/79/16 32/32/16 +f 18/18/17 50/77/17 51/80/17 19/19/17 +f 5/5/18 37/78/18 38/81/18 6/6/18 +f 32/32/19 64/79/19 33/33/19 1/1/19 +f 19/19/20 51/80/20 52/82/20 20/20/20 +f 6/6/21 38/81/21 39/83/21 7/7/21 +f 20/20/22 52/82/22 53/84/22 21/21/22 +f 7/7/23 39/83/23 40/85/23 8/8/23 +f 21/21/24 53/84/24 54/86/24 22/22/24 +f 8/8/25 40/85/25 41/87/25 9/9/25 +f 22/22/26 54/86/26 55/88/26 23/23/26 +f 9/9/27 41/87/27 42/89/27 10/10/27 +f 23/23/28 55/88/28 56/90/28 24/24/28 +f 10/10/29 42/89/29 43/91/29 11/11/29 +f 24/24/30 56/90/30 57/92/30 25/25/30 +f 11/11/31 43/91/31 44/93/31 12/12/31 +f 25/25/32 57/92/32 58/94/32 26/26/32 +f 12/12/33 44/93/33 45/65/33 13/13/33 +f 26/26/34 58/94/34 59/67/34 27/27/34 diff --git a/tools/trenchbroom/games/Neverball/assets/__tb_light_10.obj b/tools/trenchbroom/games/Neverball/assets/__tb_light_10.obj new file mode 100644 index 0000000..fee9fa3 --- /dev/null +++ b/tools/trenchbroom/games/Neverball/assets/__tb_light_10.obj @@ -0,0 +1,232 @@ +# Blender v2.79 (sub 0) OBJ File: '__tb_info_player_start.blend' +# www.blender.org +mtllib __tb_light_1.mtl +o Circle +v -0.000000 0.125000 -0.012500 +v 0.024386 0.122598 -0.012500 +v 0.047835 0.115485 -0.012500 +v 0.069446 0.103934 -0.012500 +v 0.088388 0.088388 -0.012500 +v 0.103934 0.069446 -0.012500 +v 0.115485 0.047835 -0.012500 +v 0.122598 0.024386 -0.012500 +v 0.125000 -0.000000 -0.012500 +v 0.122598 -0.024386 -0.012500 +v 0.115485 -0.047835 -0.012500 +v 0.103934 -0.069446 -0.012500 +v 0.088388 -0.088388 -0.012500 +v 0.069446 -0.103934 -0.012500 +v 0.047835 -0.115485 -0.012500 +v 0.024386 -0.122598 -0.012500 +v -0.000000 -0.125000 -0.012500 +v -0.024386 -0.122598 -0.012500 +v -0.047835 -0.115485 -0.012500 +v -0.069446 -0.103934 -0.012500 +v -0.088388 -0.088388 -0.012500 +v -0.103934 -0.069446 -0.012500 +v -0.115485 -0.047835 -0.012500 +v -0.122598 -0.024386 -0.012500 +v -0.125000 0.000000 -0.012500 +v -0.122598 0.024386 -0.012500 +v -0.115485 0.047836 -0.012500 +v -0.103934 0.069446 -0.012500 +v -0.088388 0.088388 -0.012500 +v -0.069446 0.103934 -0.012500 +v -0.047835 0.115485 -0.012500 +v -0.024386 0.122598 -0.012500 +v -0.000000 0.125000 0.012500 +v 0.024386 0.122598 0.012500 +v 0.047835 0.115485 0.012500 +v 0.069446 0.103934 0.012500 +v 0.088388 0.088388 0.012500 +v 0.103934 0.069446 0.012500 +v 0.115485 0.047835 0.012500 +v 0.122598 0.024386 0.012500 +v 0.125000 -0.000000 0.012500 +v 0.122598 -0.024386 0.012500 +v 0.115485 -0.047835 0.012500 +v 0.103934 -0.069446 0.012500 +v 0.088388 -0.088388 0.012500 +v 0.069446 -0.103934 0.012500 +v 0.047835 -0.115485 0.012500 +v 0.024386 -0.122598 0.012500 +v -0.000000 -0.125000 0.012500 +v -0.024386 -0.122598 0.012500 +v -0.047835 -0.115485 0.012500 +v -0.069446 -0.103934 0.012500 +v -0.088388 -0.088388 0.012500 +v -0.103934 -0.069446 0.012500 +v -0.115485 -0.047835 0.012500 +v -0.122598 -0.024386 0.012500 +v -0.125000 0.000000 0.012500 +v -0.122598 0.024386 0.012500 +v -0.115485 0.047836 0.012500 +v -0.103934 0.069446 0.012500 +v -0.088388 0.088388 0.012500 +v -0.069446 0.103934 0.012500 +v -0.047835 0.115485 0.012500 +v -0.024386 0.122598 0.012500 +vt 0.500000 1.000000 +vt 0.402455 0.990393 +vt 0.308658 0.961940 +vt 0.222215 0.915735 +vt 0.146447 0.853553 +vt 0.084265 0.777785 +vt 0.038060 0.691342 +vt 0.009607 0.597545 +vt 0.000000 0.500000 +vt 0.009607 0.402455 +vt 0.038060 0.308658 +vt 0.084265 0.222215 +vt 0.146447 0.146447 +vt 0.222215 0.084265 +vt 0.308658 0.038060 +vt 0.402455 0.009607 +vt 0.500000 0.000000 +vt 0.597545 0.009607 +vt 0.691342 0.038060 +vt 0.777785 0.084265 +vt 0.853554 0.146447 +vt 0.915735 0.222215 +vt 0.961940 0.308659 +vt 0.990393 0.402455 +vt 1.000000 0.500000 +vt 0.990393 0.597546 +vt 0.961940 0.691342 +vt 0.915734 0.777786 +vt 0.853553 0.853554 +vt 0.777785 0.915735 +vt 0.691341 0.961940 +vt 0.597544 0.990393 +vt 0.500000 1.000000 +vt 0.402456 0.990393 +vt 0.308659 0.961940 +vt 0.222215 0.915735 +vt 0.146447 0.853554 +vt 0.084266 0.777786 +vt 0.038060 0.691342 +vt 0.009607 0.597546 +vt 0.000000 0.500000 +vt 0.009607 0.402455 +vt 0.038060 0.308659 +vt 0.084265 0.222215 +vt 0.146446 0.146447 +vt 0.222215 0.084265 +vt 0.308658 0.038060 +vt 0.402455 0.009607 +vt 0.500000 0.000000 +vt 0.597545 0.009607 +vt 0.691342 0.038060 +vt 0.777785 0.084265 +vt 0.853553 0.146447 +vt 0.915735 0.222215 +vt 0.961940 0.308658 +vt 0.990393 0.402455 +vt 1.000000 0.500000 +vt 0.990393 0.597545 +vt 0.961940 0.691342 +vt 0.915735 0.777785 +vt 0.853553 0.853553 +vt 0.777785 0.915735 +vt 0.691342 0.961940 +vt 0.597545 0.990393 +vt 0.146447 0.146447 +vt 0.222215 0.084265 +vt 0.961940 0.691342 +vt 0.915734 0.777786 +vt 0.308658 0.038060 +vt 0.402455 0.990393 +vt 0.853553 0.853554 +vt 0.402455 0.009607 +vt 0.308658 0.961940 +vt 0.777785 0.915735 +vt 0.222215 0.915735 +vt 0.691341 0.961940 +vt 0.597545 0.009607 +vt 0.146447 0.853553 +vt 0.597544 0.990393 +vt 0.691342 0.038060 +vt 0.084265 0.777785 +vt 0.777785 0.084265 +vt 0.038060 0.691342 +vt 0.853554 0.146447 +vt 0.009607 0.597545 +vt 0.915735 0.222215 +vt 0.000000 0.500000 +vt 0.961940 0.308659 +vt 0.009607 0.402455 +vt 0.990393 0.402455 +vt 0.038060 0.308658 +vt 1.000000 0.500000 +vt 0.084265 0.222215 +vt 0.990393 0.597546 +vn 0.0000 -0.0000 -1.0000 +vn -0.0000 0.0000 1.0000 +vn 0.6344 -0.7730 0.0000 +vn -0.8819 0.4714 0.0000 +vn 0.4714 -0.8819 0.0000 +vn 0.0980 0.9952 0.0000 +vn -0.7730 0.6344 0.0000 +vn 0.2903 -0.9569 -0.0000 +vn 0.2903 0.9569 0.0000 +vn -0.6344 0.7730 0.0000 +vn 0.0980 -0.9952 0.0000 +vn 0.4714 0.8819 0.0000 +vn -0.4714 0.8819 0.0000 +vn -0.0980 -0.9952 -0.0000 +vn 0.6344 0.7730 0.0000 +vn -0.2903 0.9569 0.0000 +vn -0.2903 -0.9569 0.0000 +vn 0.7730 0.6344 0.0000 +vn -0.0980 0.9952 0.0000 +vn -0.4714 -0.8819 0.0000 +vn 0.8819 0.4714 0.0000 +vn -0.6344 -0.7730 0.0000 +vn 0.9569 0.2903 0.0000 +vn -0.7730 -0.6344 0.0000 +vn 0.9952 0.0980 0.0000 +vn -0.8819 -0.4714 0.0000 +vn 0.9952 -0.0980 0.0000 +vn -0.9569 -0.2903 0.0000 +vn 0.9569 -0.2903 0.0000 +vn -0.9952 -0.0980 0.0000 +vn 0.8819 -0.4714 0.0000 +vn -0.9952 0.0980 0.0000 +vn 0.7730 -0.6344 0.0000 +vn -0.9569 0.2903 0.0000 +usemtl mtrl/blue +s off +f 1/1/1 2/2/1 3/3/1 4/4/1 5/5/1 6/6/1 7/7/1 8/8/1 9/9/1 10/10/1 11/11/1 12/12/1 13/13/1 14/14/1 15/15/1 16/16/1 17/17/1 18/18/1 19/19/1 20/20/1 21/21/1 22/22/1 23/23/1 24/24/1 25/25/1 26/26/1 27/27/1 28/28/1 29/29/1 30/30/1 31/31/1 32/32/1 +f 33/33/2 64/34/2 63/35/2 62/36/2 61/37/2 60/38/2 59/39/2 58/40/2 57/41/2 56/42/2 55/43/2 54/44/2 53/45/2 52/46/2 51/47/2 50/48/2 49/49/2 48/50/2 47/51/2 46/52/2 45/53/2 44/54/2 43/55/2 42/56/2 41/57/2 40/58/2 39/59/2 38/60/2 37/61/2 36/62/2 35/63/2 34/64/2 +f 13/13/3 45/65/3 46/66/3 14/14/3 +f 27/27/4 59/67/4 60/68/4 28/28/4 +f 14/14/5 46/66/5 47/69/5 15/15/5 +f 1/1/6 33/33/6 34/70/6 2/2/6 +f 28/28/7 60/68/7 61/71/7 29/29/7 +f 15/15/8 47/69/8 48/72/8 16/16/8 +f 2/2/9 34/70/9 35/73/9 3/3/9 +f 29/29/10 61/71/10 62/74/10 30/30/10 +f 16/16/11 48/72/11 49/49/11 17/17/11 +f 3/3/12 35/73/12 36/75/12 4/4/12 +f 30/30/13 62/74/13 63/76/13 31/31/13 +f 17/17/14 49/49/14 50/77/14 18/18/14 +f 4/4/15 36/75/15 37/78/15 5/5/15 +f 31/31/16 63/76/16 64/79/16 32/32/16 +f 18/18/17 50/77/17 51/80/17 19/19/17 +f 5/5/18 37/78/18 38/81/18 6/6/18 +f 32/32/19 64/79/19 33/33/19 1/1/19 +f 19/19/20 51/80/20 52/82/20 20/20/20 +f 6/6/21 38/81/21 39/83/21 7/7/21 +f 20/20/22 52/82/22 53/84/22 21/21/22 +f 7/7/23 39/83/23 40/85/23 8/8/23 +f 21/21/24 53/84/24 54/86/24 22/22/24 +f 8/8/25 40/85/25 41/87/25 9/9/25 +f 22/22/26 54/86/26 55/88/26 23/23/26 +f 9/9/27 41/87/27 42/89/27 10/10/27 +f 23/23/28 55/88/28 56/90/28 24/24/28 +f 10/10/29 42/89/29 43/91/29 11/11/29 +f 24/24/30 56/90/30 57/92/30 25/25/30 +f 11/11/31 43/91/31 44/93/31 12/12/31 +f 25/25/32 57/92/32 58/94/32 26/26/32 +f 12/12/33 44/93/33 45/65/33 13/13/33 +f 26/26/34 58/94/34 59/67/34 27/27/34 diff --git a/tools/trenchbroom/games/Neverball/assets/__tb_light_5.obj b/tools/trenchbroom/games/Neverball/assets/__tb_light_5.obj new file mode 100644 index 0000000..b7dd678 --- /dev/null +++ b/tools/trenchbroom/games/Neverball/assets/__tb_light_5.obj @@ -0,0 +1,232 @@ +# Blender v2.79 (sub 0) OBJ File: '__tb_info_player_start.blend' +# www.blender.org +mtllib __tb_light_1.mtl +o Circle +v -0.000000 0.125000 -0.012500 +v 0.024386 0.122598 -0.012500 +v 0.047835 0.115485 -0.012500 +v 0.069446 0.103934 -0.012500 +v 0.088388 0.088388 -0.012500 +v 0.103934 0.069446 -0.012500 +v 0.115485 0.047835 -0.012500 +v 0.122598 0.024386 -0.012500 +v 0.125000 -0.000000 -0.012500 +v 0.122598 -0.024386 -0.012500 +v 0.115485 -0.047835 -0.012500 +v 0.103934 -0.069446 -0.012500 +v 0.088388 -0.088388 -0.012500 +v 0.069446 -0.103934 -0.012500 +v 0.047835 -0.115485 -0.012500 +v 0.024386 -0.122598 -0.012500 +v -0.000000 -0.125000 -0.012500 +v -0.024386 -0.122598 -0.012500 +v -0.047835 -0.115485 -0.012500 +v -0.069446 -0.103934 -0.012500 +v -0.088388 -0.088388 -0.012500 +v -0.103934 -0.069446 -0.012500 +v -0.115485 -0.047835 -0.012500 +v -0.122598 -0.024386 -0.012500 +v -0.125000 0.000000 -0.012500 +v -0.122598 0.024386 -0.012500 +v -0.115485 0.047836 -0.012500 +v -0.103934 0.069446 -0.012500 +v -0.088388 0.088388 -0.012500 +v -0.069446 0.103934 -0.012500 +v -0.047835 0.115485 -0.012500 +v -0.024386 0.122598 -0.012500 +v -0.000000 0.125000 0.012500 +v 0.024386 0.122598 0.012500 +v 0.047835 0.115485 0.012500 +v 0.069446 0.103934 0.012500 +v 0.088388 0.088388 0.012500 +v 0.103934 0.069446 0.012500 +v 0.115485 0.047835 0.012500 +v 0.122598 0.024386 0.012500 +v 0.125000 -0.000000 0.012500 +v 0.122598 -0.024386 0.012500 +v 0.115485 -0.047835 0.012500 +v 0.103934 -0.069446 0.012500 +v 0.088388 -0.088388 0.012500 +v 0.069446 -0.103934 0.012500 +v 0.047835 -0.115485 0.012500 +v 0.024386 -0.122598 0.012500 +v -0.000000 -0.125000 0.012500 +v -0.024386 -0.122598 0.012500 +v -0.047835 -0.115485 0.012500 +v -0.069446 -0.103934 0.012500 +v -0.088388 -0.088388 0.012500 +v -0.103934 -0.069446 0.012500 +v -0.115485 -0.047835 0.012500 +v -0.122598 -0.024386 0.012500 +v -0.125000 0.000000 0.012500 +v -0.122598 0.024386 0.012500 +v -0.115485 0.047836 0.012500 +v -0.103934 0.069446 0.012500 +v -0.088388 0.088388 0.012500 +v -0.069446 0.103934 0.012500 +v -0.047835 0.115485 0.012500 +v -0.024386 0.122598 0.012500 +vt 0.500000 1.000000 +vt 0.402455 0.990393 +vt 0.308658 0.961940 +vt 0.222215 0.915735 +vt 0.146447 0.853553 +vt 0.084265 0.777785 +vt 0.038060 0.691342 +vt 0.009607 0.597545 +vt 0.000000 0.500000 +vt 0.009607 0.402455 +vt 0.038060 0.308658 +vt 0.084265 0.222215 +vt 0.146447 0.146447 +vt 0.222215 0.084265 +vt 0.308658 0.038060 +vt 0.402455 0.009607 +vt 0.500000 0.000000 +vt 0.597545 0.009607 +vt 0.691342 0.038060 +vt 0.777785 0.084265 +vt 0.853554 0.146447 +vt 0.915735 0.222215 +vt 0.961940 0.308659 +vt 0.990393 0.402455 +vt 1.000000 0.500000 +vt 0.990393 0.597546 +vt 0.961940 0.691342 +vt 0.915734 0.777786 +vt 0.853553 0.853554 +vt 0.777785 0.915735 +vt 0.691341 0.961940 +vt 0.597544 0.990393 +vt 0.500000 1.000000 +vt 0.402456 0.990393 +vt 0.308659 0.961940 +vt 0.222215 0.915735 +vt 0.146447 0.853554 +vt 0.084266 0.777786 +vt 0.038060 0.691342 +vt 0.009607 0.597546 +vt 0.000000 0.500000 +vt 0.009607 0.402455 +vt 0.038060 0.308659 +vt 0.084265 0.222215 +vt 0.146446 0.146447 +vt 0.222215 0.084265 +vt 0.308658 0.038060 +vt 0.402455 0.009607 +vt 0.500000 0.000000 +vt 0.597545 0.009607 +vt 0.691342 0.038060 +vt 0.777785 0.084265 +vt 0.853553 0.146447 +vt 0.915735 0.222215 +vt 0.961940 0.308658 +vt 0.990393 0.402455 +vt 1.000000 0.500000 +vt 0.990393 0.597545 +vt 0.961940 0.691342 +vt 0.915735 0.777785 +vt 0.853553 0.853553 +vt 0.777785 0.915735 +vt 0.691342 0.961940 +vt 0.597545 0.990393 +vt 0.146447 0.146447 +vt 0.222215 0.084265 +vt 0.961940 0.691342 +vt 0.915734 0.777786 +vt 0.308658 0.038060 +vt 0.402455 0.990393 +vt 0.853553 0.853554 +vt 0.402455 0.009607 +vt 0.308658 0.961940 +vt 0.777785 0.915735 +vt 0.222215 0.915735 +vt 0.691341 0.961940 +vt 0.597545 0.009607 +vt 0.146447 0.853553 +vt 0.597544 0.990393 +vt 0.691342 0.038060 +vt 0.084265 0.777785 +vt 0.777785 0.084265 +vt 0.038060 0.691342 +vt 0.853554 0.146447 +vt 0.009607 0.597545 +vt 0.915735 0.222215 +vt 0.000000 0.500000 +vt 0.961940 0.308659 +vt 0.009607 0.402455 +vt 0.990393 0.402455 +vt 0.038060 0.308658 +vt 1.000000 0.500000 +vt 0.084265 0.222215 +vt 0.990393 0.597546 +vn 0.0000 -0.0000 -1.0000 +vn -0.0000 0.0000 1.0000 +vn 0.6344 -0.7730 0.0000 +vn -0.8819 0.4714 0.0000 +vn 0.4714 -0.8819 0.0000 +vn 0.0980 0.9952 0.0000 +vn -0.7730 0.6344 0.0000 +vn 0.2903 -0.9569 -0.0000 +vn 0.2903 0.9569 0.0000 +vn -0.6344 0.7730 0.0000 +vn 0.0980 -0.9952 0.0000 +vn 0.4714 0.8819 0.0000 +vn -0.4714 0.8819 0.0000 +vn -0.0980 -0.9952 -0.0000 +vn 0.6344 0.7730 0.0000 +vn -0.2903 0.9569 0.0000 +vn -0.2903 -0.9569 0.0000 +vn 0.7730 0.6344 0.0000 +vn -0.0980 0.9952 0.0000 +vn -0.4714 -0.8819 0.0000 +vn 0.8819 0.4714 0.0000 +vn -0.6344 -0.7730 0.0000 +vn 0.9569 0.2903 0.0000 +vn -0.7730 -0.6344 0.0000 +vn 0.9952 0.0980 0.0000 +vn -0.8819 -0.4714 0.0000 +vn 0.9952 -0.0980 0.0000 +vn -0.9569 -0.2903 0.0000 +vn 0.9569 -0.2903 0.0000 +vn -0.9952 -0.0980 0.0000 +vn 0.8819 -0.4714 0.0000 +vn -0.9952 0.0980 0.0000 +vn 0.7730 -0.6344 0.0000 +vn -0.9569 0.2903 0.0000 +usemtl mtrl/red +s off +f 1/1/1 2/2/1 3/3/1 4/4/1 5/5/1 6/6/1 7/7/1 8/8/1 9/9/1 10/10/1 11/11/1 12/12/1 13/13/1 14/14/1 15/15/1 16/16/1 17/17/1 18/18/1 19/19/1 20/20/1 21/21/1 22/22/1 23/23/1 24/24/1 25/25/1 26/26/1 27/27/1 28/28/1 29/29/1 30/30/1 31/31/1 32/32/1 +f 33/33/2 64/34/2 63/35/2 62/36/2 61/37/2 60/38/2 59/39/2 58/40/2 57/41/2 56/42/2 55/43/2 54/44/2 53/45/2 52/46/2 51/47/2 50/48/2 49/49/2 48/50/2 47/51/2 46/52/2 45/53/2 44/54/2 43/55/2 42/56/2 41/57/2 40/58/2 39/59/2 38/60/2 37/61/2 36/62/2 35/63/2 34/64/2 +f 13/13/3 45/65/3 46/66/3 14/14/3 +f 27/27/4 59/67/4 60/68/4 28/28/4 +f 14/14/5 46/66/5 47/69/5 15/15/5 +f 1/1/6 33/33/6 34/70/6 2/2/6 +f 28/28/7 60/68/7 61/71/7 29/29/7 +f 15/15/8 47/69/8 48/72/8 16/16/8 +f 2/2/9 34/70/9 35/73/9 3/3/9 +f 29/29/10 61/71/10 62/74/10 30/30/10 +f 16/16/11 48/72/11 49/49/11 17/17/11 +f 3/3/12 35/73/12 36/75/12 4/4/12 +f 30/30/13 62/74/13 63/76/13 31/31/13 +f 17/17/14 49/49/14 50/77/14 18/18/14 +f 4/4/15 36/75/15 37/78/15 5/5/15 +f 31/31/16 63/76/16 64/79/16 32/32/16 +f 18/18/17 50/77/17 51/80/17 19/19/17 +f 5/5/18 37/78/18 38/81/18 6/6/18 +f 32/32/19 64/79/19 33/33/19 1/1/19 +f 19/19/20 51/80/20 52/82/20 20/20/20 +f 6/6/21 38/81/21 39/83/21 7/7/21 +f 20/20/22 52/82/22 53/84/22 21/21/22 +f 7/7/23 39/83/23 40/85/23 8/8/23 +f 21/21/24 53/84/24 54/86/24 22/22/24 +f 8/8/25 40/85/25 41/87/25 9/9/25 +f 22/22/26 54/86/26 55/88/26 23/23/26 +f 9/9/27 41/87/27 42/89/27 10/10/27 +f 23/23/28 55/88/28 56/90/28 24/24/28 +f 10/10/29 42/89/29 43/91/29 11/11/29 +f 24/24/30 56/90/30 57/92/30 25/25/30 +f 11/11/31 43/91/31 44/93/31 12/12/31 +f 25/25/32 57/92/32 58/94/32 26/26/32 +f 12/12/33 44/93/33 45/65/33 13/13/33 +f 26/26/34 58/94/34 59/67/34 27/27/34 diff --git a/tools/trenchbroom/games/Neverball/initial_neverball_map.map b/tools/trenchbroom/games/Neverball/initial_neverball_map.map new file mode 100644 index 0000000..c3f88fb --- /dev/null +++ b/tools/trenchbroom/games/Neverball/initial_neverball_map.map @@ -0,0 +1,96 @@ +// Game: Neverball +// Format: Quake3 +// entity 0 +{ +"classname" "worldspawn" +"back" "map-back/clouds.sol" +"_tb_def" "builtin:neverball.fgd" +"grad" "back/land.png" +"message" "Welcome." +"song" "bgm/track1.ogg" +// brush 0 +{ +( -72 -72 80 ) ( -72 -72 64 ) ( -72 200 64 ) mtrl/turf-grey 0 0 0 0.5 0.5 0 0 0 +( -72 200 64 ) ( -72 -72 64 ) ( -64 -64 64 ) mtrl/turf-grey 0 0 0 0.5 0.5 0 0 0 +( -64 -64 80 ) ( -72 -72 80 ) ( -72 200 80 ) mtrl/edge-green-offset 0 0 0 0.5 0.5 0 0 0 +( -64 -64 64 ) ( -72 -72 64 ) ( -72 -72 80 ) mtrl/invisible -192 0 0 0.5 1 0 0 0 +( -64 192 64 ) ( -64 192 80 ) ( -72 200 80 ) mtrl/invisible -192 0 0 0.5 1 0 0 0 +( -64 -64 64 ) ( -64 -64 80 ) ( -64 192 80 ) mtrl/invisible -192 0 0 0.5 1 0 0 0 +} +// brush 1 +{ +( -64 192 80 ) ( -64 -64 80 ) ( -64 -64 64 ) mtrl/invisible -64 0 0 0.5 1 0 0 0 +( -64 -64 64 ) ( -64 -64 80 ) ( 64 -64 80 ) mtrl/invisible 64 0 0 0.5 1 0 0 0 +( 64 192 64 ) ( -64 192 64 ) ( -64 -64 64 ) mtrl/turf-grey 0 0 0 0.5 0.5 0 0 0 +( 64 -64 80 ) ( -64 -64 80 ) ( -64 192 80 ) mtrl/turf-green-small 0 0 0 0.5 0.5 0 0 0 +( 64 192 80 ) ( -64 192 80 ) ( -64 192 64 ) mtrl/invisible 64 0 0 0.5 1 0 0 0 +( 64 192 64 ) ( 64 -64 64 ) ( 64 -64 80 ) mtrl/invisible -64 0 0 0.5 1 0 0 0 +} +// brush 2 +{ +( -64 192 80 ) ( -64 64 80 ) ( -64 64 64 ) mtrl/invisible -128 0 0 0.5 1 0 0 0 +( 64 64 80 ) ( 64 64 64 ) ( -64 64 64 ) mtrl/invisible -128 0 0 0.5 1 0 0 0 +( 64 64 64 ) ( 64 192 64 ) ( -64 192 64 ) mtrl/invisible -128 128 0 0.5 0.5 0 0 0 +( 64 192 80 ) ( 64 64 80 ) ( -64 64 80 ) mtrl/goal -128 128 0 0.5 0.5 0 0 0 +( -64 192 64 ) ( 64 192 64 ) ( 64 192 80 ) mtrl/invisible -128 0 0 0.5 1 0 0 0 +( 64 192 80 ) ( 64 192 64 ) ( 64 64 64 ) mtrl/invisible -128 0 0 0.5 1 0 0 0 +} +// brush 3 +{ +( 64 192 64 ) ( 64 192 80 ) ( 64 -64 80 ) mtrl/invisible -192 0 0 0.5 1 0 0 0 +( 64 -64 64 ) ( 64 -64 80 ) ( 72 -72 80 ) mtrl/invisible -192 0 0 0.5 1 0 0 0 +( 64 192 64 ) ( 72 200 64 ) ( 72 200 80 ) mtrl/invisible -192 0 0 0.5 1 0 0 0 +( 72 -72 64 ) ( 72 200 64 ) ( 64 192 64 ) mtrl/turf-grey 0 0 0 0.5 0.5 0 0 0 +( 64 192 80 ) ( 72 200 80 ) ( 72 -72 80 ) mtrl/edge-green-offset 0 0 0 0.5 0.5 0 0 0 +( 72 200 80 ) ( 72 200 64 ) ( 72 -72 64 ) mtrl/turf-grey 0 0 0 0.5 0.5 0 0 0 +} +// brush 4 +{ +( -64 -64 80 ) ( -72 -72 80 ) ( -72 -72 64 ) mtrl/invisible -64 0 0 0.5 1 0 0 0 +( 72 -72 80 ) ( 72 -72 64 ) ( -72 -72 64 ) mtrl/turf-grey 0 0 0 0.5 0.5 0 0 0 +( 72 -72 64 ) ( 64 -64 64 ) ( -64 -64 64 ) mtrl/turf-grey 0 0 0 0.5 0.5 0 0 0 +( 64 -64 80 ) ( 72 -72 80 ) ( -72 -72 80 ) mtrl/edge-green-offset 0 0 0 0.5 0.5 0 0 0 +( -64 -64 64 ) ( 64 -64 64 ) ( 64 -64 80 ) mtrl/invisible -192 0 0 0.5 1 0 0 0 +( 64 -64 80 ) ( 64 -64 64 ) ( 72 -72 64 ) mtrl/invisible 160 0 0 0.5 1 0 0 0 +} +// brush 5 +{ +( -72 200 64 ) ( -72 200 80 ) ( -64 192 80 ) mtrl/invisible -32 0 0 0.5 1 0 0 0 +( 64 192 80 ) ( 64 192 64 ) ( -64 192 64 ) mtrl/invisible -192 0 0 0.5 1 0 0 0 +( -64 192 64 ) ( 64 192 64 ) ( 72 200 64 ) mtrl/turf-grey 0 0 0 0.5 0.5 0 0 0 +( 72 200 80 ) ( 64 192 80 ) ( -64 192 80 ) mtrl/edge-green-offset 0 0 0 0.5 0.5 0 0 0 +( 72 200 64 ) ( 72 200 80 ) ( -72 200 80 ) mtrl/turf-grey 0 0 0 0.5 0.5 0 0 0 +( 72 200 64 ) ( 64 192 64 ) ( 64 192 80 ) mtrl/invisible -64 0 0 0.5 1 0 0 0 +} +// brush 6 +{ +( -64 64 80 ) ( -64 -64 80 ) ( -64 -64 64 ) mtrl/invisible -128 0 0 0.5 1 0 0 0 +( 64 -64 80 ) ( 64 -64 64 ) ( -64 -64 64 ) mtrl/invisible -128 0 0 0.5 1 0 0 0 +( 64 -64 64 ) ( 64 64 64 ) ( -64 64 64 ) mtrl/invisible -128 128 0 0.5 0.5 0 0 0 +( 64 64 80 ) ( 64 -64 80 ) ( -64 -64 80 ) mtrl/arrow-green-light -128 128 0 0.5 0.5 0 0 0 +( -64 64 64 ) ( 64 64 64 ) ( 64 64 80 ) mtrl/invisible -128 0 0 0.5 1 0 0 0 +( 64 64 80 ) ( 64 64 64 ) ( 64 -64 64 ) mtrl/invisible -128 0 0 0.5 1 0 0 0 +} +} +// entity 1 +{ +"classname" "info_player_start" +"origin" "0 0 104" +} +// entity 2 +{ +"classname" "info_player_deathmatch" +"origin" "0 128 104" +} +// entity 3 +{ +"classname" "target_position" +"origin" "0 64 80" +"targetname" "camera_target" +} +// entity 4 +{ +"classname" "info_player_intermission" +"origin" "-200 -168 224" +"target" "camera_target" +} diff --git a/tools/trenchbroom/games/Neverball/neverball.fgd b/tools/trenchbroom/games/Neverball/neverball.fgd new file mode 100644 index 0000000..5246ad3 --- /dev/null +++ b/tools/trenchbroom/games/Neverball/neverball.fgd @@ -0,0 +1,190 @@ +// Unofficial Neverball FGD for use in TrenchBroom +// Details were taken from https://github.com/Neverball/neverball-docs/blob/8e4b71c0eea12f5cab8d925964682fb2eaee625e/Entities.md and co. +// After those turned out to be insufficient, mapc.c was consulted for reference. +// Yet, this may still be inaccurate in the fine details. + +@BaseClass = NeverballBody : "internal class; 'bodies' are described in the manual, but incompletely" +[ + // These all being properties of 'body' is a weird undocumented quirk of mapc - that is actually used in Neverball to some extent. + target(target_destination) : "An optional path for the body to move along. This also specifies the origin of the body relative to the path." + target2(target_destination) : "An optional secondary path to specifically control the body's rotation." + material(string) : "Optional fallback material override filename. Must appear in the MAP file before 'model' to work. For standard map materials, prefix 'textures/'." + model(string) : "An optional filename of an OBJ file. The geometry in this is added, without collision, to this entity." +] + +@SolidClass base(NeverballBody) = worldspawn : "Defines level attributes and static geometry." +[ + // Ig imp + version(string) : "The level version number. It is split into a major and minor version; major version updates must occur if an update would break replays (i.e. the physics of the level changes in any way), while minor version updates are used for purely cosmetic changes (addition of decals, for example). This is written as follows: '0.0'." : "0.0" + goal(integer) : "Neverball: The amount of coins required to be able to use a goal." + time(integer) : "Neverball: The time limit (as hundredths-of-seconds, or centiseconds; 6000 would be one minute)." + idle(integer) : "Neverputt: In hundredths-of-seconds (similar to Neverball 'time'), the amount of time to wait after the ball stops. It is stated in the manual that this is useful when there are moving objects that could push the ball. It is not stated in the manual, but it is reasonable to conclude that as such, one should set this based on the longest cycle period of any moving object a stopped ball could encounter." + par(integer) : "Neverputt: The 'par' amount of turns any individual player is expected to take on a course." + + // Menu + author(string) : "The name(s) of the level designer(s)." + shot(string) : "The filename of the 'level screenshot' for the menu." + time_hs(string) : "The initial values in the high-scores table for Best Time, in the order: Hard, Medium, Easy. (On at least one occasion, the last entry has been missing, so take this under advisement should a map's value here seem odd.) Example: '1000 2000 3000'. The numbers are in the same form as the time limit, and this defaults to said time limit." + goal_hs(string) : "See 'time_hs' ; however, this is for the Fast Unlock category. This is still time-based." + coin_hs(string) : "Similar in format to 'time_hs' and 'goal_hs', but instead of time values, represents the amount of coins collected, for Most Coins. As such, the default is the minimum amount of coins required to complete the level (see 'goal')." + bonus(choices) : "By being set to 1, makes this level a bonus level. Omit otherwise." : 1 = + [ + 1 : "Bonus Level" + ] + // Ig unimp + message(string) : "The message shown on level start. A backslash (\\) starts a new line - wrapping is not automatic." + back(choices) : "The compiled background level file." : "map-back/alien.sol" = + [ + "" : "" + "map-back/alien.sol" : "Alien" + "map-back/blank.sol" : "Blank" + "map-back/city.sol" : "City" + "map-back/clouds.sol" : "Clouds" + "map-back/jupiter.sol" : "Jupiter" + "map-back/ocean.sol" : "Ocean" + "map-back/volcano.sol" : "Volcano" + ] + grad(choices) : "A background gradient. Should usually be chosen to fit the background level file. There are other gradients not in the list, for brevity." : "back/land.png" = + [ + "back/alien.png" : "Alien (Alien)" + "back/city.png" : "City (City)" + "back/land.png" : "Land (Clouds)" + "back/space.png" : "Space (Jupiter)" + "back/ocean.png" : "Ocean (Ocean)" + "back/volcano.png" : "Volcano (Volcano)" + ] + song(choices) : "The background music file." : "bgm/title.ogg" = + [ + "" : "" + "bgm/title.ogg" : "Neverball: Title" + "bgm/inter.ogg" : "Neverball: Intermission / Browsing" + "bgm/track1.ogg" : "Neverball: Track 1" + "bgm/track2.ogg" : "Neverball: Track 2" + "bgm/track3.ogg" : "Neverball: Track 3" + "bgm/track4.ogg" : "Neverball: Track 4" + "bgm/track5.ogg" : "Neverball: Track 5" + "bgm/track6.ogg" : "Neverball: Track 6" + ] +] + +// Of course, as you may have surmised, this is reliant on OBJ support... +@PointClass size(-16 -16 -24, 16 16 8) model("__tb_info_player_start.obj") = info_player_start : "The player start. In Neverball, there should only be one; in Neverputt, one must be defined per player slot. Beware! Rotating this entity will not work; the angle must always be 0. Usually accompanied by a mtrl/arrow* detail-brush decal." +[ + angle(integer) : "The starting angle - completely ignored, mind! - is always 90, or towards +Y." : 90 + radius(float) : "The radius, in 'meters' (1 meter = 64 units). Defaults to 0.25, but if in Neverputt, this should be set to 0.0625." : "0.25" +] + +@PointClass size(32 32 48) model("__tb_info_player_deathmatch.obj") = info_player_deathmatch : "The goal (or one thereof). For Neverball, usually accompanied by a mtrl/goal detail-brush decal. For Neverputt, usually in a hole." +[ + radius(float) : "The radius, in 'meters' (1 meter = 64 units). Defaults to 0.75 (though be aware that the collision rules make this effectively 0.5). In Neverputt, usually 0.1375." : "0.75" +] + +// Items need to have their boxes be sized 32x32x32 for accurate placement on coin pads. +// Then they need custom models because the actual real models have three issues: +// 1. They don't match any other Neverball units +// (& we can't just change the definition of the units, since it'd break misc_model, which we can't work around) +// 2. They're manually coloured +// 3. A WYSIWYG approach for grow/shrink items is rather unhelpful +// So I'm adding more models. +@PointClass + size(32 32 32) + model({{ + light >= 10 -> "__tb_light_10.obj", + light >= 5 -> "__tb_light_5.obj", + "__tb_light_1.obj" + }}) = + light : "Neverball: A coin. Usually accompanied by a 'coin pad' (mtrl/coin-*)." +[ + light(choices) : "The amount of coins this individual coin counts as." : 1 = + [ + 1 : "1 coin (light, yellow)" + 5 : "5 coins (medium, red)" + 10 : "10 coins (dark, blue)" + ] +] + +// For shrink & grow objects, the boxes in practice need to be sized to whatever the "recommended" item height is. +@PointClass size(32 32 32) model("__tb_item_health_small.obj") = item_health_small : "A 'shrink' item. Shrinks the ball to 50% of it's original size. If it was grown previously, it instead reverts. If already shrunk, it does nothing." [] +@PointClass size(32 32 32) model("__tb_item_health_large.obj") = item_health_large : "A 'grow' item. Grows the ball to 150% of it's original size. If it was shrunk previously, it instead reverts. If already grown, it does nothing." [] + +// These extend a unit upwards from their origins so that they aren't embedded in the brush below. + +@PointClass size(-32 -32 0, 32 32 1) model("__tb_generic_ring_05.obj") = target_teleporter : "A teleporter. Usually accompanied by a mtrl/teleporter detail-brush decal." +[ + radius(float) : "The radius, in 'meters' (1 meter = 64 units). Defaults to 0.5." : "0.5" + target(target_destination) : "A target_position entity that is the destination of the teleporter. Two-way teleporters have target_position entities at each other's exits." +] + +@PointClass size(-32 -32 0, 32 32 1) model("__tb_generic_ring_05.obj") = info_camp : "A switch. Usually accompanied by a mtrl/switch detail-brush decal." +[ + radius(float) : "The radius, in 'meters' (1 meter = 64 units). Defaults to 0.5." : "0.5" + target(target_destination) : "The path_corner that is turned on/off by this switch." + state(choices) : "The initial state of the switch. Should always match the initial state of the path_corner." : 0 = + [ + 0 : "Disabled" + 1 : "Enabled" + ] + timer(float) : "The amount of time, in seconds, that the switch remains active for. Defaults to 0, which is infinite." : "0" + invisible(choices) : "Allows making the switch invisible." : 0 = + [ + 0 : "Visible" + 1 : "Invisible" + ] +] + +// -- Ok, over to the utility & vis objects -- + +@PointClass size(32 32 32) = info_player_intermission : "The camera position for level begin. Neverputt uses two (begin, then main menu, based on .map file order); Neverball meanwhile isn't *documented* as using two, but map-medium/title.map does use two (presumably for the animated title title)." +[ + target(target_destination) : "A target_position entity that the camera tries to look at." +] + +@PointClass size(32 32 32) model("__tb_fancy_path_corner.obj") = path_corner : "Represents a point on a path, and describes the journey to the next point on the path." +[ + targetname(target_source) : "The name of this point." + target(target_destination) : "The name of the next point." + speed(float) : "The amount of time it takes to get to the next point, in seconds. Defaults to 1.0." : "1.0" + state(choices) : "Controls whether objects may move along this path by default. Defaults to enabled." : 1 = + [ + 0 : "Disabled" + 1 : "Enabled" + ] + smooth(choices) : "Controls whether the objects accelerate/decelerate, or simply move at constant speed. Defaults to acceleration/deceleration." : 1 = + [ + 0 : "Linear" + 1 : "Smooth" + ] + angles(string) : "Euler angles in the form of degrees 'pitch yaw roll', such as '0 90 0', when the object is at this point." + angle(integer) : "A single angle, equivalent to only adjusting Yaw of the angles value." +] + +@SolidClass base(NeverballBody) = func_train : "A moving object." [] + +// Yes, misc_model MAY be used as a brush entity; yes, geometry in a misc_model works properly. +@SolidClass base(NeverballBody) model(model) = misc_model : "A dummy body entity." [] +@PointClass base(NeverballBody) model(model) = misc_model : "A dummy body entity." [] + +@PointClass = target_position : "An abstract point referred to by other entities." +[ + targetname(target_source) : "The name of this point." +] + +// Finally... the background thing? + +@PointClass = info_null : "A billboard." +[ + dist(float) : "The distance from the centre of the world to the billboard." : "250" + flag(Flags) = + [ + 1: "Position relative to bottom edge" : 0 + 2: "Billboard is flat/horizontal" : 0 + ] + image(string) : "The billboard's image." + xrot(string) : "3 X positioning angles (one after the other, separated by spaces); static, dynamic, quadratic (play with these and see what happens)" + yrot(string) : "3 Y positioning angles (one after the other, separated by spaces); static, dynamic, quadratic (play with these and see what happens)" + zrot(string) : "3 Z positioning angles (one after the other, separated by spaces); static, dynamic, quadratic (play with these and see what happens)" + width(string) : "The width" + height(string) : "The height" + time(float) : "The length of the animation." +] + diff --git a/tools/trenchbroom/games/Quake/GameConfig.cfg b/tools/trenchbroom/games/Quake/GameConfig.cfg new file mode 100644 index 0000000..be3b487 --- /dev/null +++ b/tools/trenchbroom/games/Quake/GameConfig.cfg @@ -0,0 +1,77 @@ +{ + "version": 9, + "name": "Quake", + "icon": "Icon.png", + "fileformats": [ + { "format": "Valve" }, + { "format": "Standard" } + ], + "filesystem": { + "searchpath": "id1", + "packageformat": { "extension": ".pak", "format": "idpak" } + }, + "materials": { + "root": "textures", + "extensions": [".D"], + "palette": "gfx/palette.lmp", + "attribute": "wad" + }, + "entities": { + "definitions": [ "Quake.fgd", "Quoth2.fgd", "Rubicon2.def", "Teamfortress.fgd" ], + "defaultcolor": "0.6 0.6 0.6 1.0" + }, + "tags": { + "brush": [ + { + "name": "Detail", + "attribs": [], + "match": "classname", + "pattern": "func_detail*" + }, + { + "name": "Trigger", + "attribs": [ "transparent" ], + "match": "classname", + "pattern": "trigger*", + "material": "trigger" // set this material when tag is enabled + }, + { + "name": "Func", + "attribs": [], + "match": "classname", + "pattern": "func*" + } + ], + "brushface": [ + { + "name": "Clip", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "clip" + }, + { + "name": "Skip", + "match": "material", + "pattern": "skip" + }, + { + "name": "Hint", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "hint*" + }, + { + "name": "Liquid", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "\**" + } + ] + }, + "softMapBounds":"-4096 -4096 -4096 4096 4096 4096", + "compilationTools": [ + { "name": "qbsp"}, + { "name": "vis"}, + { "name": "light"} + ] +} diff --git a/tools/trenchbroom/games/Quake/Icon.png b/tools/trenchbroom/games/Quake/Icon.png new file mode 100644 index 0000000..d670041 Binary files /dev/null and b/tools/trenchbroom/games/Quake/Icon.png differ diff --git a/tools/trenchbroom/games/Quake/Quake.fgd b/tools/trenchbroom/games/Quake/Quake.fgd new file mode 100644 index 0000000..9772cc8 --- /dev/null +++ b/tools/trenchbroom/games/Quake/Quake.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" [] diff --git a/tools/trenchbroom/games/Quake/Quoth2.fgd b/tools/trenchbroom/games/Quake/Quoth2.fgd new file mode 100644 index 0000000..10f5c41 --- /dev/null +++ b/tools/trenchbroom/games/Quake/Quoth2.fgd @@ -0,0 +1,1584 @@ +// +// Quoth game definition file (.fgd) +// for Worldcraft 1.6 and above +// + +// Quoth additions by Preach(andrew.denner@btinternet.com) +// From the base quake.fgd from CZG +// +// worldspawn +// + +@SolidClass = worldspawn : "World entity" +[ + message(string) : "Text on entering the world" + worldtype(choices) : "Ambience" : 0 = + [ + 0 : "Medieval" + 1 : "Runic (metal)" + 2 : "Present (base)" + 3 : "Elder" + ] + sounds(integer) : "CD track to play" : 1 + light(integer) : "Ambient light" + _sunlight(integer) : "Sunlight" + _sun_mangle(string) : "Sun mangle (Yaw pitch roll)" + gravity(integer) : "Set gravity for this level (default 800)" + keep_keys(choices) : "Player retains keys between levels" : 0 = + [ + 0 : "Keys are lost, as usual" + 1 : "Send keys to next map, don't get keys from previous map" + 2 : "Get keys from previous map, don't send over to next map " + 3 : "Send and get keys" + ] + lose_items(choices) : "Player's inventory" : 0 = + [ + 0 : "Player keeps weapons, ammo and health" + 1 : "Player is reset to shotgun, 25 shells, 100 health" + ] + aflag(integer) : "Enable optimisations(see tutorial for details)" + sky(string) : "Set a skybox" + corpse_time(choices) : "Corpse removal delay" : 0 = + [ + -1 : "Corpses stay" + ] + noise1(string) : "Triggered ambient 1" + noise2(string) : "Triggered ambient 2" + noise3(string) : "Triggered ambient 3" + noise4(string) : "Triggered ambient 4" +] + +// +// base marker definitions +// + +@BaseClass = Appearflags [ + spawnflags(Flags) = + [ + 256 : "Not in Easy" : 0 + 512 : "Not in Normal" : 0 + 1024 : "Not in Hard" : 0 + 2048 : "Not in Deathmatch" : 0 + ] + quothflags(choices) : "Coopflags" : 0 = + [ + 0 : "(no coop flags)" + 4096 : "Not in coop" + 8192 : "Only in coop" + ] +] + +@BaseClass = Targetname [ targetname(target_source) : "Name" ] +@BaseClass = Target [ + target(target_destination) : "Target" + killtarget(target_destination) : "Killtarget" + message(string) : "Message on trigger" + delay(string) : "Delay before trigger" +] + +@BaseClass base(Targetname, Target) = AllTargets [ + targetname2(target_destination) : "2nd Name" + targetname3(target_destination) : "3rd Name" + targetname4(target_destination) : "4th Name" + target2(target_destination) : "2nd Target" + target3(target_destination) : "3rd Target" + target4(target_destination) : "4th Target" + killtarget2(target_destination) : "Extra 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 : "DM start" [] +@PointClass size(-32 -32 0, 32 32 64) base(PlayerClass, Targetname) = info_teleport_destination : "Teleport destination" [] +@PointClass = info_null : "info_null (spotlight target)" +[ + targetname(target_source) : "Name" +] + +//info_notnull is not defined, to allow both Brush and Point entities to be created without issue + +@PointClass base(Appearflags, Target, Targetname) = info_logic_insolid : "Test point is in solid" [] +@PointClass base(Appearflags, Target, Targetname) = info_logic_inopen : "Test point is in open" [] +@PointClass base(Appearflags, AllTargets) = info_logic_random : "Trigger targets at random" [ + chance(string) : "Activation probability" + spawnflags(Flags) = + [ + 1 : "Branch" : 0 + ] +] + +@PointClass base(Appearflags, Target) = info_gug_seismometer: "Detect earthquakes from gugs" +[ + health(string): "Threshold of damage to trigger" +] + + +@PointClass base(Appearflags) = info_intermission : "Intermission camera" +[ + mangle(string) : "Mangle (Pitch Yaw Roll)" + message(string) : "Finale Text" +] + +@BaseClass = Deathtype [ + deathtype(string) : "Obituary message" +] +// +// items +// +@BaseClass base(Target, Targetname) = Item +[ + ritem(choices) : "Respawning" : 0 = + [ + 0 : "Respawning off" + 1 : "Respawning on" + ] + respawndelay(integer) : "Respawn delay" + respawncount(integer) : "Respawn count" + +] +@BaseClass size(0 0 0, 32 32 32) color(80 0 200) base(Item, Appearflags) = 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 + size(0 0 0, 32 16 32) + 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 : "Perforator/Nailgun ammo" [] + +@PointClass + size(0 0 0, 32 32 16) + base(Appearflags) + model( + {{ + spawnflags & 2 -> ":maps/b_bh100.bsp", + spawnflags & 1 -> ":maps/b_bh10.bsp", + ":maps/b_bh25.bsp" + }} + ) = + item_health : "Health pak" + [ + spawnflags(flags) = + [ + 1 : "Rotten" : 0 + 2 : "Megahealth" : 0 + ] +] + +@PointClass base(Item, Appearflags) model({ "path": ":progs/suit.mdl" }) = + item_artifact_envirosuit : "Environmental protection suit" [] +@PointClass base(Item, Appearflags) model({ "path": ":progs/quaddama.mdl" }) = + item_artifact_super_damage : "Quad damage" [] +@PointClass base(Item, Appearflags) model({ "path": ":progs/invulner.mdl" }) = + item_artifact_invulnerability : "Pentagram of Protection" [] +@PointClass base(Item, Appearflags) model({ "path": ":progs/invisibl.mdl" }) = + item_artifact_invisibility : "Ring of Shadows" [] +@PointClass base(Item, Appearflags) model({ "path": ":progs/cross.mdl" }) = + item_artifact_cross : "Cross of Deflection" [] +@PointClass base(Item, Appearflags) model({ "path": ":progs/trinity.mdl" }) = + item_artifact_trinity : "Trinity" [] + +@PointClass size(-16 -16 0, 16 16 56) base(Item, Appearflags) model({ "path": ":progs/armor.mdl", "skin": 2 }) = + item_armorInv : "200% armor (Red)" [] +@PointClass size(-16 -16 0, 16 16 56) base(Item, Appearflags) model({ "path": ":progs/armor.mdl", "skin": 1 }) = + item_armor2 : "150% armor (Yellow)" [] +@PointClass size(-16 -16 0, 16 16 56) base(Item, Appearflags) model({ "path": ":progs/armor.mdl" }) = + item_armor1 : "100% armor (Green)" [] +@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 + ] +] + +@PointClass base(Item, Appearflags) model({ "path": ":progs/flashlight.mdl" }) = + item_flashlight : "Flashlight" [] + +@SolidClass = func_group : "Group of brushes for in-editor use" [ +_phong(string) : "Applies Phong to this entity"] +@SolidClass = func_detail : "Group of brushes for certain compilers" [ +_phong(string) : "Applies Phong to this entity"] +@SolidClass = func_detail_illusionary : "func_detail variant with no collision (players / monsters / gunfire) and doesn't split world faces." [ +_phong(string) : "Applies Phong to this entity"] +@SolidClass = func_detail_wall : "func_detail variant that doesn't split world faces." [ +_phong(string) : "Applies Phong to this entity"] + +// +// weaponses +// + +@BaseClass size(-16 -16 0, 16 16 32) color(0 0 200) base(Item, Appearflags) = Weapon [] + +@PointClass base(Weapon) model({ "path": ":progs/g_shot.mdl" }) = weapon_supershotgun : "Super shotgun" [] +@PointClass base(Weapon) model({ "path": ":progs/g_nail.mdl" }) = weapon_nailgun : "Nailgun" [] +@PointClass base(Weapon) model({ "path": ":progs/g_nail2.mdl" }) = weapon_supernailgun : "Perforator" [] +@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" [] +@PointClass base(Weapon) model({ "path": ":progs/v_ham.mdl" }) = weapon_hammer : "Warhammer" [] +@PointClass base(Weapon) model({ "path": ":progs/v_lance.mdl" }) = weapon_plasmagun : "Plasma Gun" [] +@PointClass base(Weapon) model({ "path": ":progs/v_bomb.mdl" }) = weapon_bomb : "The Bomb" [] + + +// +// badasses +// + +@BaseClass base(Appearflags, Target, Targetname) color(220 0 0) = Monster +[ + spawnflags(Flags) = + [ + 1 : "Ambush" : 0 + 32 : "Teleport Silently" : 0 + 64 : "Teleport Spawn" : 0 + 128 : "Alert When Teleported" : 0 + ] + spawndelay(choices) : "Spawn Delay" : 0 = + [ + -1 : "Short random delay" + ] + corpse_time(choices) : "Corpse removal delay" : 0 = + [ + -1 : "Corpses stay" + ] +] + +@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/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 48) model({ "path": ":progs/shalrath.mdl" }) = monster_shalrath : "Shalrath" [] +@PointClass base(Monster) size(32 32 48) model({ "path": ":progs/tarbaby.mdl" }) = monster_tarbaby : "Tarbaby" [] +@PointClass base(Monster) size(32 32 48) 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 + ] +] + +//quoth monsters + +@PointClass base(Monster) size(-16 -16 -24, 16 16 40) model({ "path": ":progs/bob.mdl" }) = monster_bob : "Bob" [] +@PointClass base(Monster) size(-16 -16 -24, 16 16 40) model({ "path": ":progs/soldier.mdl", "skin": 1 }) = monster_army_rocket : "Rocketeer" [] +@PointClass base(Monster) size(-16 -16 -24, 16 16 40) model({ "path": ":progs/enforcer.mdl", "skin": 1 }) = monster_defender: "Defender" [] +@PointClass base(Monster) size(-16 -16 -24, 16 16 40) model({ "path": ":progs/enforcer.mdl", "skin": 2 }) = monster_pyro: "Pyro" [] +@PointClass base(Monster) size(-16 -16 -24, 16 16 40) model({ "path": ":progs/enforcer.mdl", "skin": 3 }) = monster_eliminator: "Eliminator" [] +@PointClass base(Monster) size(-32 -32 -24, 32 32 64) model({ "path": ":progs/scor.mdl" }) = monster_scourge: "Centroid" [] +@PointClass base(Monster) size(-16 -16 -24, 16 16 40) model({ "path": ":progs/sentinel.mdl" }) = monster_sentinel: "Sentinel" +[ + spawnflags(Flags) = + [ + 4 : "Nail sentinel" : 0 + ] +] +@PointClass base(Monster) size(-32 -32 -24, 32 32 64) model({ "path": ":progs/edie.mdl" }) = monster_edie: "Edie" [] +@PointClass base(Monster) size(-32 -32 -24, 32 32 64) model({ "path": ":progs/ogre.mdl", "skin": 1 }) = monster_ogre_flak: "Flak Ogre" [] +@PointClass base(Monster) size(-16 -16 -24, 16 16 32) + model( + {{ + dangle == "1" -> { "path": ":progs/voreling.mdl", "skin": 0, "frame": 13 }, + ":progs/voreling.mdl" + }} + ) = +monster_voreling: "Voreling" +[ + dangle(choices) : "Dangling" : 0 = + [ + 0 : "On floor" + 1 : "On ceiling" + ] +] +@PointClass base(Monster) size(-16 -16 -24, 16 16 40) + model( + {{ + startonground == "1" -> ":progs/polyp.mdl", + { "path": ":progs/polyp.mdl", "skin": 0, "frame": 153 } + }} + ) = +monster_polyp: "Polyp" +[ + startonground(choices) : "Starting pose" : 0 = + [ + 0 : "Flying" + 1 : "On ground" + ] +] + +@PointClass base(Monster) size(-16 -16 -24, 16 16 40) model({ "path": ":progs/hknight.mdl" }) = monster_death_knight : "Death knight" [] +@PointClass base(Monster) size(-16 -16 -24, 16 16 40) model({ "path": ":progs/dguard.mdl" }) = monster_death_guard : "Death guard" [] +@PointClass base(Monster) size(-16 -16 -24, 16 16 40) model({ "path": ":progs/hknight.mdl", "skin": 1 }) = monster_death_lord : "Death lord" [] + + +@PointClass base(Monster) size(-32 -32 -24, 32 32 64) + model( + {{ + perch == "1" -> ":progs/gaunt.mdl", + { "path": ":progs/gaunt.mdl", "skin": 0, "frame": 24 } + }} + ) = +monster_gaunt : "Gaunt" +[ + perch(choices) : "Starting pose" : 0 = + [ + 0 : "Flying" + 1 : "On ground" + ] +] + +@PointClass base(Monster) size(-32 -32 -24, 32 32 64) model({ "path": ":progs/drole.mdl" }) = monster_drole: "Drole" [] +@PointClass base(Monster) size(-32 -32 -24, 32 32 64) model({ "path": ":progs/gug.mdl" }) = monster_gug: "Gug" [] +@PointClass base(Monster) size(-64 -64 -448, 64 64 256) + model( + {{ + coiled == "1" -> { "path": ":progs/vermis.mdl", "skin": 0, "frame": 2 }, + { "path": ":progs/vermis.mdl", "skin": 0, "frame": 52 } + }} + ) = +monster_vermis: "Vermis" +[ + coiled(choices) : "Starting pose" : 0 = + [ + 0 : "Full height" + 1 : "Coiled up" + ] + skin(choices) : "Skin effect" : 0 = + [ + 0 : "Regular" + 1 : "Fades to black at tail" + 2 : "Slime glow at tail" + 3 : "Lava glow at tail" + ] +] + + + +// +// lights +// +@BaseClass color(255 255 40) = Static [ + spawnflags(Flags) = + [ + 1 : "Force Static" : 0 + 2 : "Force Dynamic" : 0 + ] +] + +@BaseClass color(255 255 40) = Grill [ + spawnflags(Flags) = + [ + 1 : "Force Static" : 0 + 2 : "Solid Blocking" : 0 + ] +] + +@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" + ] + 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 lightsource" + [ + spawnflags(Flags) = [ 1 : "Initially dark" : 0 ] + ] +@PointClass size(-8 -8 -8, 8 8 8) base(Light, Target, Targetname) = + light_fluoro : "Fluorescent light" + [ + spawnflags(Flags) = [ 1 : "Initially dark" : 0 ] + ] +@PointClass size(-8 -8 -8, 8 8 8) base(Light, Target) = + light_fluorospark : "Sparking fluorescent light" + [ + ] + +@PointClass size(-8 -8 -12, 8 8 20) base(Light, Target, Targetname, Static) model({ "path": ":progs/flame2.mdl" }) = + light_flame_large_yellow : "Large yellow flame" [] +@PointClass size(-4 -4 -12, 4 4 20) base(Light, Target, Targetname, Static) model({ "path": ":progs/flame2.mdl" }) = + light_flame_small_yellow : "Small yellow flame" + [] +@PointClass size(-4 -4 -12, 4 4 20) base(Light, Target, Targetname, Static) model({ "path": ":progs/flame2.mdl" }) = + light_flame_small_white : "Small white flame" + [ + spawnflags(Flags) = [ 1 : "Initially dark" : 0 ] + ] +@PointClass size(-4 -4 -12, 4 4 20) base(Light, Target, Targetname, Static) model({ "path": ":progs/flame.mdl" }) = + light_torch_small_walltorch : "Small walltorch" [] + + // quoth lights + +@PointClass size(-8 -8 -8, 8 8 8) base(Light, Target, Targetname, Static) model({ "path": ":progs/lightpost.mdl" }) = + light_postlight : "Post light" + [ + spawnflags(Flags) = [ 1 : "Initially dark" : 0 ] + color(choices) : "Colour of light object" : 0 = + [ + 0 : "Yellow-white" + 1 : "Blue-white" + 2 : "Red" + ] + ] +@PointClass size(-8 -8 -8, 8 8 8) base(Light, Target, Targetname, Static) model({ "path": ":progs/lighttube.mdl" }) = + light_tubelight : "Tube light" + [ + spawnflags(Flags) = [ 1 : "Initially dark" : 0 ] + color(choices) : "Colour of light object" : 0 = + [ + 0 : "Yellow-white" + 1 : "Blue-white" + 2 : "Red" + ] + ] + +@PointClass size(-8 -8 -8, 8 8 8) base(Light, Target, Targetname, Static) = + light_globe : "Globe light" + [ + color(choices) : "Colour of globe" : 0 = + [ + 0 : "Gold" + 1 : "Red" + 2 : "Green" + 3 : "Blue" + 4 : "White" + 5 : "Evile" + 6 : "Evile zombie" + ] + ] + +@PointClass size(-8 -8 -8, 8 8 8) base(Light, Target, Targetname) = + light_marsh : "Marsh lights" + [ + color(choices) : "Colour of globe" : 0 = + [ + 0 : "white ( default )" + 1 : "bluish white" + 2 : "blue" + 3 : "green" + 4 : "orange" + 5 : "red" + 6 : "purple" + ] + ] + + +@PointClass size(-8 -8 -48, 8 8 80) base(Light, Target, Targetname, Static) model({ "path": ":progs/longtrch.mdl" }) = + light_torch_long_walltorch : "Long wall torch" [] +@PointClass size(-8 -8 -16, 8 8 8) + base(Light, Target, Targetname, Static) + model( + {{ + skin == "5" -> { "path": ":progs/brazshrt.mdl", "skin": 5 }, + skin == "4" -> { "path": ":progs/brazshrt.mdl", "skin": 4 }, + skin == "3" -> { "path": ":progs/brazshrt.mdl", "skin": 3 }, + skin == "2" -> { "path": ":progs/brazshrt.mdl", "skin": 2 }, + skin == "1" -> { "path": ":progs/brazshrt.mdl", "skin": 1 }, + ":progs/brazshrt.mdl" + }} + ) = + light_flame_brazier_short : "Short brazier" + [ + skin(choices) : "Texture" : 0 = + [ + 0 : "knave ( default ) " + 1 : "rust " + 2 : "redbrick " + 3 : "copper " + 4 : "altar " + 5 : "wizmet" + ] + ] +@PointClass size(-8 -8 -64, 8 8 8) + base(Light, Target, Targetname, Static) + model( + {{ + skin == "5" -> { "path": ":progs/braztall.mdl", "skin": 5 }, + skin == "4" -> { "path": ":progs/braztall.mdl", "skin": 4 }, + skin == "3" -> { "path": ":progs/braztall.mdl", "skin": 3 }, + skin == "2" -> { "path": ":progs/braztall.mdl", "skin": 2 }, + skin == "1" -> { "path": ":progs/braztall.mdl", "skin": 1 }, + ":progs/braztall.mdl" + }} + ) = + light_flame_brazier_tall : "Tall brazier" + [ + skin(choices) : "Texture" : 0 = + [ + 0 : "knave ( default ) " + 1 : "rust " + 2 : "redbrick " + 3 : "copper " + 4 : "altar " + 5 : "wizmet" + ] + ] + +@PointClass size(-8 -8 -8, 8 8 8) base(Static, Appearflags) + model({ + "path" : model, + "skin" : skin, + "frame": frame + }) + = mapobject_custom: "Custom mapobject" + [ + model(string) : "Model" + frame(integer) : "Frame" + skin(string) : "Skin" + mangle(string) : "Angles(overrides angle above)" + ] + +@PointClass size(-8 -8 -8, 8 8 8) base(Static, Targetname, Appearflags) = mapobject_waterfall: "Waterfall mapobject" + [ + skin(choices) : "Skin": 0 = + [ + 0 : "Clean water" + 1 : "Dirty water" + 2 : "Blood" + 3 : "Slime" + 4 : "Lava" + ] + frame(integer) : "Initial frame" + mangle(string) : "Angles(overrides angle above)" + sounds(choices) : "Sound effects": 0 = + [ + 0 : "Sounds Off" + 1 : "Sounds On" + ] + noise(string) : "Custom active sound" + noise1(string) : "Custom stop sound" + speed(integer) : "Attenuation of sound" : 0 + volume(integer) : "Volume (0 - 1)" + spawnflags(flags) = + [ + 1 : "Initially dry" : 0 + ] + ] + +@PointClass size(-8 -8 -8, 8 8 8) base(Grill, Appearflags) = mapobject_grill: "Custom grill mapobject" + [ + model(string) : "Model" + frame(string) : "Frame" + mangle(string) : "Angles(overrides angle above)" + ] + +@PointClass size(-8 -8 -8, 8 8 8) base(Grill, Appearflags) = mapobject_grill128: "128 unit grill mapobject" + [ + frame(choices) : "Frame": 0 = + [ + 0 : "Red idbase grill" + 1 : "Dark idbase grill" + 2 : "Rusty idbase grill" + 3 : "Pale idbase grill" + 4 : "Large vent grid" + 5 : "Large vent - horizontal bars" + 6 : "Slimy brown floor grills" + 7 : "Wizmet medium grid panels" + 8 : "Wizmet fine grid panels" + 9 : "Fury square floor panels" + 10 : "Fury small floor panels" + 11 : "Copper floor panels" + 12 : "Copper floor grill" + 13 : "Copper grill with warning trim" + 14 : "Rusted diagonal wire mesh" + 15 : "Beaten diagonal wire mesh" + 16 : "Bright square wire mesh" + 17 : "Stained square wire mesh" + 18 : "Warning pattern wire mesh" + 19 : "Rusted square wire mesh" + 20 : "Knave steel strut pattern" + 22 : "Knave gold strut pattern" + 24 : "Knave rust strut pattern" + 26 : "Knave red strut pattern" + 28 : "Knave blue strut pattern" + ] + + mangle(string) : "Angles(overrides angle above)" + ] +@PointClass size(-8 -8 -8, 8 8 8) base(Grill, Appearflags) = mapobject_grill64: "64 unit grill mapobject" + [ + frame(choices) : "Frame": 0 = + [ + 0 : "Red idbase grill" + 1 : "Dark idbase grill" + 2 : "Rusty idbase grill" + 3 : "Pale idbase grill" + 4 : "Small vent grid" + 5 : "Small vent - horizontal bars" + 6 : "Slimy brown floor grills" + 7 : "Wizmet medium grid panels" + 8 : "Wizmet fine grid panels" + 9 : "Fury square floor panels" + 10 : "Fury small floor panels" + 11 : "Copper floor panels" + 12 : "Copper floor grill" + 13 : "Copper grill with warning trim" + 14 : "Rusted diagonal wire mesh" + 15 : "Beaten diagonal wire mesh" + 16 : "Bright square wire mesh" + 17 : "Stained square wire mesh" + 18 : "Warning pattern wire mesh" + 19 : "Rusted square wire mesh" + 20 : "Knave steel strut pattern" + 21 : "Knave steel pentagram" + 22 : "Knave gold strut pattern" + 23 : "Knave gold pentagram" + 24 : "Knave rust strut pattern" + 25 : "Knave rust pentagram" + 26 : "Knave red strut pattern" + 27 : "Knave red pentagram" + 28 : "Knave blue strut pattern" + 29 : "Knave blue pentagram" + ] + mangle(string) : "Angles(overrides angle above)" + ] + +@PointClass base(Static, Appearflags) size(-16 -16 -24, 16 16 40) model({ "path": ":progs/corpse_imp.mdl", "skin": 7, "frame": 9 }) = corpse_crucified1 : "Corpse(crucified)" [] +@PointClass base(Static, Appearflags) size(-16 -16 -24, 16 16 40) model({ "path": ":progs/corpse_imp.mdl", "skin": 8, "frame": 10 }) = corpse_crucified2 : "Corpse(crucified,headless)" [] + +@PointClass base(Static, Appearflags) size(-16 -16 -96, 16 16 0) model({ "path": ":progs/corpse_lynch.mdl" }) = corpse_lynched1 : "Corpse(lynched,clothed)" [] +@PointClass base(Static, Appearflags) size(-16 -16 -96, 16 16 0) model({ "path": ":progs/corpse_lynch.mdl", "skin": 1}) = corpse_lynched2 : "Corpse(lynched)" [] +@PointClass base(Static, Appearflags) size(-16 -16 -96, 16 16 0) model({ "path": ":progs/corpse_lynch.mdl", "skin": 2, "frame": 1 }) = corpse_lynched3 : "Corpse(lynched,eaten)" [] + +@PointClass base(Static, Appearflags) size(-16 -16 -96, 16 16 0) model({ "path": ":progs/corpse_flay.mdl" }) = corpse_flayed1 : "Corpse(flayed,clothed)" [] +@PointClass base(Static, Appearflags) size(-16 -16 -96, 16 16 0) model({ "path": ":progs/corpse_flay.mdl", "skin": 1 }) = corpse_flayed2 : "Corpse(flayed)" [] +@PointClass base(Static, Appearflags) size(-16 -16 -96, 16 16 0) model({ "path": ":progs/corpse_flay.mdl", "skin": 2, "frame": 2 }) = corpse_flayed3 : "Corpse(flayed,eaten)" [] +@PointClass base(Static, Appearflags) size(-16 -16 -96, 16 16 0) model({ "path": ":progs/corpse_flay.mdl", "skin": 1, "frame": 1 }) = corpse_flayed4 : "Corpse(flayed,broken leg)" [] + + +@PointClass base(Static, Appearflags) size(-32 -32 -40, 32 32 0) model({ "path": ":progs/corpse_imp.mdl" }) = corpse_impaled_back1 : "Corpse(impaled in back,clothed)" [] +@PointClass base(Static, Appearflags) size(-32 -32 -40, 32 32 0) model({ "path": ":progs/corpse_imp.mdl", "skin": 1 }) = corpse_impaled_back2 : "Corpse(impaled in back)" [] +@PointClass base(Static, Appearflags) size(-32 -32 -40, 32 32 0) model({ "path": ":progs/corpse_imp.mdl", "skin": 2, "frame": 1 }) = corpse_impaled_back3 : "Corpse(impaled in back,eaten)" [] + + +@PointClass base(Static, Appearflags) size(-16 -16 -24, 16 16 16) model({ "path": ":progs/corpse_imp.mdl", "skin": 0, "frame": 2 }) = corpse_impaled_front1 : "Corpse(impaled in front,clothed)" [] +@PointClass base(Static, Appearflags) size(-16 -16 -24, 16 16 16) model({ "path": ":progs/corpse_imp.mdl", "skin": 1, "frame": 2 }) = corpse_impaled_front2 : "Corpse(impaled in front)" [] +@PointClass base(Static, Appearflags) size(-16 -16 -24, 16 16 16) model({ "path": ":progs/corpse_imp.mdl", "skin": 3, "frame": 3 }) = corpse_impaled_front3 : "Corpse(impaled in front,eaten)" [] + + +@PointClass base(Static, Appearflags) size(-16 -16 -24, 16 16 16) model({ "path": ":progs/corpse_imp.mdl", "skin": 0, "frame": 4 }) = + corpse_impaled_horizontal1 : "Corpse(impaled horizontal,clothed)" [] +@PointClass base(Static, Appearflags) size(-16 -16 -24, 16 16 16) model({ "path": ":progs/corpse_imp.mdl", "skin": 1, "frame": 4 }) = + corpse_impaled_horizontal2 : "Corpse(impaled horizontal)" [] +@PointClass base(Static, Appearflags) size(-16 -16 -24, 16 16 16) model({ "path": ":progs/corpse_imp.mdl", "skin": 4, "frame": 5 }) = + corpse_impaled_horizontal3 : "Corpse(impaled horizontal,nibbled)" [] +@PointClass base(Static, Appearflags) size(-16 -16 -24, 16 16 16) model({ "path": ":progs/corpse_imp.mdl", "skin": 5, "frame": 6 }) = + corpse_impaled_horizontal4 : "Corpse(impaled horizontal,eaten)" [] + + +@PointClass base(Static, Appearflags) size(-16 -16 -24, 16 16 16) model({ "path": ":progs/corpse_imp.mdl", "skin": 0, "frame": 7 }) = + corpse_impaled_vertical1 : "Corpse(impaled vertical,clothed)" [] +@PointClass base(Static, Appearflags) size(-16 -16 -24, 16 16 16) model({ "path": ":progs/corpse_imp.mdl", "skin": 1, "frame": 7 }) = + corpse_impaled_vertical2 : "Corpse(impaled vertical)" [] +@PointClass base(Static, Appearflags) size(-16 -16 -24, 16 16 16) model({ "path": ":progs/corpse_imp.mdl", "skin": 6, "frame": 8 }) = + corpse_impaled_vertical3 : "Corpse(impaled vertical,eaten)" [] + + + +// +// misc +// + +@PointClass base(Appearflags) = air_bubbles : "Air bubbles" [] +@PointClass base(Appearflags, Targetname) = + event_lightning : "Chthon's lightning" [] +@PointClass base(Appearflags) = misc_fireball : "Small fireball" + [ speed(integer) : "Speed" : 40 ] +@PointClass size(0 0 0, 32 32 64) model({ "path": ":maps/b_explob.bsp" }) = misc_explobox : "Large nuclear container" [] +@PointClass size(0 0 0, 32 32 32) model({ "path": ":maps/b_exbox2.bsp" }) = misc_explobox2 : "Small nuclear container" [] + +@PointClass size(0 0 0, 32 32 64) model({ "path": ":progs/b_bio_l.bsp" }) = misc_biobox : "Large bio-waste container" [] +@PointClass size(0 0 0, 32 32 32) model({ "path": ":progs/b_bio_s.bsp" }) = misc_biobox2 : "Small bio-waste container" [] +@PointClass size(0 0 0, 32 32 64) model({ "path": ":progs/b_plas_l.bsp" }) = misc_plasmabox_l : "Large plasma container" [] +@PointClass size(0 0 0, 32 32 32) model({ "path": ":progs/b_plas_s.bsp" }) = misc_plasmabox_s : "Small plasma container" [] + + +@SolidClass = func_illusionary : "Static model" +[ +] +@PointClass base(Targetname) = trap_spikeshooter : "Triggered shooter" +[ + spawnflags(Flags) = + [ + 1 : "Superspike" : 0 + 2 : "Laser" : 0 + ] +] +@PointClass base(trap_spikeshooter) = trap_shooter : "Continuous shooter" [] + +// +// ambient sounds +// + +@PointClass = ambient_drip : "Dripping sound" [] +@PointClass = ambient_drone : "Engine/machinery sound" [] +@PointClass = ambient_comp_hum : "Computer background sounds" [] +@PointClass = ambient_flouro_buzz : "Fluorescent buzzing sound" [] +@PointClass = ambient_light_buzz : "Buzzing sound from light" [] +@PointClass = ambient_suck_wind : "Wind sound" [] +@PointClass = ambient_swamp1 : "Frogs croaking" [] +@PointClass = ambient_swamp2 : "Frogs croaking B" [] +@PointClass = ambient_thunder : "Thunder sound" [] +@PointClass = ambient_generalpurpose : "Custom ambient sound" + [ + noise(string) : "Sound file to play" + speed(integer) : "Attenuation of sound" : 0 + volume(integer) : "Volume (0 - 1)" + ] + +@PointClass base( Targetname, Appearflags) = play_sound_triggered : "Custom sound trigger" + [ + noise(string) : "Sound file to play" + speed(integer) : "Attenuation of sound" : 0 + volume(integer) : "Volume (0 - 1)" + impulse(integer) : "Channel" + wait(integer) : "Wait before retrigger" : 0 + ] + +@PointClass base( Targetname, Appearflags) = play_sound : "Repeated custom sound" + [ + noise(string) : "Sound file to play" + speed(integer) : "Attenuation of sound" : 0 + volume(integer) : "Volume (0 - 1)" + impulse(integer) : "Channel" + wait(integer) : "Random time between sounds" : 0 + delay(integer) : "Minimum time between sounds" : 2 + ] + +@BaseClass = Command + [ + spawnflags(Flags) = + [ + 2 : "Command only to activator" : 0 + 4 : "Set as 'onload command' on use" : 0 + ] + ] +@PointClass base(Appearflags, Targetname, Command) = info_command : "Target-fired command to clients" + [ + message(string) : "Console command" + ] +@SolidClass base(Appearflags, Command) = trigger_command : "Trigger: Command to clients" + [ + message(string) : "Console command" + ] + +@PointClass base(Appearflags) = info_command_spawn : "Command to clients on spawn" + [ + message(string) : "Console command" + ] + +@SolidClass base(Appearflags) = trigger_command_contact : "Trigger: Command on entry" + [ + message(string) : "Console command" + spawnflags(Flags) = + [ + 4 : "Set as 'onload command' on use" : 0 + ] + ] +@PointClass base (Appearflags,Targetname) = info_command_server : "Target-fired command to server" + [ + message(string) : "Console command" + ] + + +@PointClass base (Appearflags, Targetname) = info_bomb : "Triggered explosion"[] + +@PointClass base (Appearflags, Targetname) = info_effect_pulse : "Pulses of lights" + [ + mangle(string) : "Angles (override)" + speed(integer) : "Speed" + wait(choices) : "Wait between pulses" = + [ + -1 : "Does not refire" + ] + ] + +@BaseClass = Spawner +[ + spawnclassname(string) : "Desired classname" + spawnfunction(string) : "Desired classname(must match above)" + count(integer): "Number of spawns" + awake(choices) : "Monster state on spawn" : 0 = + [ + 0 : "Idle" + 1 : "Awake" + ] +] +@PointClass base (Appearflags, Targetname, Spawner) = info_multispawn : "Spawn multiple monsters" +[ + wait(integer) : "Wait between spawns" +] + +@PointClass base( Appearflags, Targetname, Spawner) = info_groupspawn : "Spawn monster group" +[ + lip(integer) : "Gap between monsters" + t_width(integer) : "Width of row" +] + +@PointClass base (Appearflags, Targetname) = info_screenshake : "Earthquake event" +[ + ltime(integer) : "Duration of quake" + lip(integer) : "Frequency of shaking" + height(integer) : "Strength of quake" : 500 + multiplier(integer) : "Strength multiplier" : 1 + noise(string) : "Looping sound" + noise1(string) : "Ending sound" +] + + +@PointClass base (Appearflags, Target) = info_endgate : "Info endgate" +[ + mapindex(integer) : "Map index" + spawnflags(Flags) = + [ + 1 : "Inverse logic" : 0 + ] +] +@PointClass base (info_endgate) = info_mapgate : "Info mapgate" [] + +@PointClass base (Appearflags, Targetname, Deathtype) = info_trap : "Custom shooter" +[ + preset(choices) : "Preset" : 0 = + [ + 0 : "No preset" + 1 : "Player Rockets" + 2 : "Player Grenades" + 3 : "Player Plasma" + 4 : "Player Nails" + 5 : "Player Super Nails" + ] + target(string) : "Target to fire towards" + modelpath(string) : "Projectile model" + wait(integer) : "Wait between shots" + delay(integer) : "Delay for first shot" : 0 + speed(integer) : "Projectile speed" : 600 + mindamage(integer) : "Minimum projectile damage" : 20 + maxdamage(integer) : "Maximum projectile damage" + dmg(integer) : "Radius of blast" : 0 + duration(integer) : "Projectile fuse" : 5 + style(choices) : "Projectile flight" : 0 = + [ + 0 : "Flying" + 1 : "Ballistic (Explode on Impact)" + 2 : "Bounce (grenade)" + ] + noise(string) : "Firing sound" + noise1(string) : "Impact sound" + noise2(string) : "Bounce sound(grenade only)" + tracking(choices) : "Projectile tracking" : 0 = + [ + 0 : "None" + 1 : "Vore style" + 2 : "Death Lord/Rocketeer style" + ] + multiplier(integer) : "Func_breakable damage multiplier" + flashlight(choices) : "Projectile glow" : 0 = + [ + 0 : "Glow off" + 1 : "Glow on" + ] +] + +@PointClass base (Appearflags, Targetname, Deathtype) = trap_lightning_triggered : "Triggered Lightning Trap" +[ + target(string) : "Target to fire towards" + duration(string) : "Beam duration" : "0.1" //daft thing doesn't have a sensible number class, so fractions are strings... + dmg(integer) : "Damage" : 30 + noise(string) : "Firing sound" + style(choices) : "Beam type" : 0 = + [ + 0 : "Thinner beam" + 1 : "Wider beam" + ] + spawnflags(flags) = + [ + 1 : "Boom" : 0 + ] +] + +@BaseClass = Breakable [ + preset(choices): "Preset" : 0 = + [ + 0 : "Rock" + 1 : "Wood" + 2 : "Flesh" + 3 : "Machine" + 4 : "Glass" + 5 : "Brick(8 unit)" + 6 : "Brick(16 unit)" + 7 : "Brick(32 unit)" + 8 : "Metal" + 9 : "Circuitboard" + ] + ritem(choices): "Skin(rock.wood.glass.brick.metal)" = + [ + 0: "Ochre.Medi.Gray.Wiz.Cr8top" + 1: "Moss.Driftwood.Dark.Cityochre.Cr8side" + 2: "Cobalt.Rotten.Bone.Ctyred.panel" + 3: "Black.Cord.Sepia.Ctycrack.Tech09" + 4: "Earth.Pine.Brown.Ctygreen.Idbase" + 5: "Grave.Red_wiz.Ale.IKBlue.Compbrown" + 6: "Red.Dark_wiz.Bottle.P_blue.Compgrey" + 7: "Grey.Crate.Green.Red.Sfloor" + 8: "Rock3_7.=.Sun.Off-grey.Tech red" + 9: "Rock3_8.=.Gold.Mayan.Speedbase" + 10:"Mayan.=.Orange.Grey.Mmetal1_8" + 11:"Knave.=.Blood.Eggshell.Wizmet" + 12:"Azfloor.=.Crimson.=.Wizmet blue" + 13:"'crete.=.Blue.=.Wizmet green" + 14:"Ice. = .Sapphire. = .Dark copper" + 15:"White. = . = . = .Light copper" + 16:"=.=.=.=.Metal5_8" + 17:"=.=.=.=.Metal4_5" + 18:"=.=.=.=.Metal4_4" + 19:"=.=.=.=.Metal2_4" + 20:"=.=.=.=.Mmetal1_1" + 21:"=.=.=.=.Cop1_3" + 22:"=.=.=.=.Cop1_6" + 23:"=.=.=.=.Metal1_2" + 24:"=.=.=.=.Knave bronze" + 25:"=.=.=.=.Knave rust" + 26:"=.=.=.=.Weathered tin" + 27:"=.=.=.=.Circuits(olive)" + 28:"=.=.=.=.Circuits(sea-green)" + ] + count(integer) : "Number of fragments" + health(integer) : "Health" + noise(choices) : "Breaking sound" = + [ + "" : "Preset default" + "impact/wood_bk.wav" : "Wood crack" + "player/gib.wav" : "Player gib" + "impact/mach_bk.wav" : "Machine explosion" + "progs/glass.mdl" : "Glass shatter" + "impact/rockbrk.wav" : "Rock crumble" + "impact/metal_bk.wav" : "Metal shearing" + ] + noise1(choices) : "Bounce sound 1" = + [ + "" : "Preset default" + "impact/wood_i1.wav" : "Wood1" + "zombie/z_miss.wav" : "Flesh1" + "impact/glass_i1.wav" : "Glass1" + "impact/rock1.wav" : "Rock1" + "impact/metal_i1.wav" : "Metal1" + ] + noise2(choices) : "Bounce sound 2" = + [ + "" : "Preset default" + "impact/wood_i2.wav" : "Wood2" + "impact/gib_i2.wav": "Flesh2" + "impact/glass_i2.wav" : "Glass2" + "impact/rock2.wav" : "Rock2" + "impact/metal_i2.wav" : "Metal2" + ] + noise3(choices) : "Bounce sound 3" = + [ + "" : "Preset default" + "impact/wood_i3.wav" : "Wood3" + "impact/gib_i3.wav": "Flesh3" + "impact/glass_i3.wav" : "Glass3" + "impact/rock3.wav" : "Rock3" + "impact/metal_i3.wav" : "Metal3" + ] + noise4(choices) : "Bounce sound 4" = + [ + "" : "Preset default" + "impact/wood_i4.wav" : "Wood4" + "impact/gib_i4.wav": "Flesh4" + "impact/glass_i4.wav" : "Glass4" + "impact/rock4.wav" : "Rock4" + "impact/metal_i4.wav" : "Metal4" + ] + + modelpath(string) : "Custom rubble model" + rsize(integer) : "Minimum rubble frame" + t_width(integer) : "Maximum rubble frame" +] + +@BaseClass = Shadow +[ + _shadow(choices) : "Shadows settings" : 1 = + [ + 0: "Casts no shadows" + 1: "Casts shadows" + ] +] + +@BaseClass = Selfshadow +[ + _selfshadow(choices) : "Self-shadows settings" : 1 = + [ + 0: "Casts no shadows" + 1: "Casts shadows on itself" + ] +] + + + +@SolidClass base(Appearflags, Targetname, Breakable, Selfshadow) = func_breakable : "Breakable object" +[ + spawnflags(Flags) = + [ + 1 : "Explosion on death" : 0 + ] +] + +@PointClass base(Appearflags, Targetname, Breakable) = info_rubble : "Spawn rubble" +[ +] + + +// +// moving things +// + + +@SolidClass base(Appearflags, Targetname, Target, Deathtype, Selfshadow) = func_door : "Basic door" +[ + speed(integer) : "Speed" : 100 + sounds(choices) : "Sound" : 0 = + [ + 0: "No sounds" + 1: "Stone" + 2: "Machine" + 3: "Stone Chain" + 4: "Screechy Metal" + 5: "Custom sounds" + ] + noise2(string) : "Move sound" + noise1(string) : "Stop sound" + wait(string) : "Delay before close" : "4" + lip(integer) : "Lip" : 8 + dmg(integer) : "Damage inflicted when blocked" : 0 + health(integer) : "Health (shoot open)" : 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, Selfshadow) = func_door_secret : "Triggered door" +[ + t_width(integer) : "First move length" + t_length(integer) : "Second move length" + dmg(integer) : "Damage when blocked" : 2 + wait(string) : "Time before close" : "2" + sounds(choices) : "Sounds" : 3 = + [ + 1: "Medieval" + 2: "Metal" + 3: "Base" + ] + spawnflags(flags) = + [ + 1 : "Open once only" : 0 + 2 : "Moves left first" : 0 + 4 : "Moves down first" : 0 + 8 : "Not shootable" : 0 + 16 : "Always shootable" : 0 + ] +] + +@SolidClass base(Targetname, Appearflags, Shadow) = func_wall : "Wall" [] + +@SolidClass base(Targetname, Target, Selfshadow) = func_button : "Button" +[ + speed(integer) : "Speed" : 40 + lip(integer) : "Lip" : 4 + health(integer) : "Health (shootable if > 0)" + sounds(choices) : "Sounds" = + [ + 0 : "Steam metal" + 1 : "Wooden clunk" + 2 : "Metallic clink" + 3 : "In-out" + ] + wait(string) : "Delay before reset" : "1" +] + +@SolidClass base(Targetname, Selfshadow) = func_door_button : "Door-mounted Button" +[ + bind(target_source) : "Name of door to bind to" +] + + +@PointClass base(Targetname) model({ "path": ":progs/teleport.mdl" }) = func_teleporttrain : "Moving teleport destination" +[ + speed(integer) : "Speed (units per second)" : 64 + target(target_source) : "First stop target" +] + +@SolidClass base(Targetname, Deathtype, Selfshadow) = func_train : "Moving platform" +[ + sounds(choices) : "Sound" : 1 = + [ + 0: "None" + 1: "Ratchet Metal" + ] + speed(integer) : "Speed (units per second)" : 64 + target(target_source) : "First stop target" + dmg(integer) : "Damage on crush" : 0 + count(integer) : "Number of clones" : 0 + spawnflags(Flags) = + [ + 1 : "Smooth" : 0 + 2 : "Blockable" : 0 + ] +] + +@PointClass base(Targetname) size(16 16 16) = + path_corner : "Moving platform stop" +[ + target(target_source) : "Next stop target" + wait(integer) : "Wait" : 0 + event(target_source) : "Event to fire on arrival" + duration(integer) : "Movetime for next motion(if set)" + speed(integer) : "Speed for next motion(if set)" +] + +@PointClass base(Targetname) size(16 16 16) = + path_corner_precise : "Advanced monster waypoint" +[ + target(target_source) : "Next waypoint" + wait(integer) : "Wait" : 0 +] + +@PointClass base(Targetname) size(16 16 16) = + path_corner_contact : "Monster waypoint" +[ + target(target_source) : "Next waypoint" +] + +@SolidClass base(Targetname, Deathtype) = func_togglewall : "Toggleable wall" +[ + spawnflags(Flags) = + [ + 1 : "Starts off" : 0 + 2 : "Particles" : 0 + 4 : "Monsters ignore" : 0 + ] + dmg(integer) : "Contact damage" + wait(string) : "Wait between damage" : "0.5" + noise(string) : "Toggle off sound" + noise1(string) : "Toggle on sound" + noise2(string) : "Damage sound" + speed(integer) : "Particle speed" : 75 + style(integer) : "Particle count" : 10 + color(integer) : "Particle colour" + worldtype(choices) : "particle direction" : 0 = + [ + 0 : "Up" + 1 : "Down" + 2 : "East" + 3 : "West" + 4 : "North" + 5 : "South" + ] + +] + +@SolidClass base(Targetname) = func_particlefield : "particle burst effect" +[ + event(string) : "Group name" + cnt(integer) : "Index within group" + wait(string) : "Delay between flashes" : "0.2" + count(integer) : "Particle count" : 2 + color(integer) : "Particle colour" : 192 +] + +@SolidClass base(Targetname, Selfshadow) = func_plat : "Elevator" +[ + spawnflags(Flags) = + [ + 1 : "Low trigger" : 0 + ] + speed(integer) : "Speed" : 150 + height(integer) : "Travel altitude (can be negative)" : 0 + sounds(choices) : "Sound group" : 1 = + [ + 0: "None" + 1: "Base fast" + 2: "Chain Slow" + ] +] + +@SolidClass base(Shadow) = func_episodegate : "Episode Gate" +[ + spawnflags(Flags) = + [ + 1 : "Episode 1" : 1 + 2 : "Episode 2" : 0 + 4 : "Episode 3" : 0 + 8 : "Episode 4" : 0 + ] +] + +@SolidClass base(Shadow) = func_bossgate : "Boss gate" [] + +// +// triggers +// + +@BaseClass base(AllTargets) = Trigger +[ + sounds(choices) : "Sound style" : 0 = + [ + 0 : "None" + 1 : "Secret sound" + 2 : "Beep beep" + 3 : "Large switch" + 4 : "Set message to text string" + ] + spawnflags(flags) = [ 2: "Broadcast message" : 0 ] + noise(string) : "Custom noise(set sounds 4)" +] + +@SolidClass base(Target) = trigger_changelevel : "Trigger: Change level" +[ + map(string) : "New map name" + spawnflags(flags) = + [ + 1: "No Intermission" : 0 + ] +] + +@SolidClass base(Trigger) = trigger_once : "Trigger: Activate once" +[ + health(integer) : "Health" + spawnflags(flags) = [ 1: "Entity only" : 0 ] +] +@SolidClass base(Trigger) = trigger_multiple : "Trigger: Activate multiple" +[ + wait(string) : "Wait before reset" : "4" + health(integer) : "Health" + spawnflags(flags) = [ 1: "Entity only" : 0 ] +] +@SolidClass base(Trigger) = trigger_onlyregistered : "Trigger: Registered only" +[ + spawnflags(flags) = [ 1: "Entity only" : 0 ] +] +@SolidClass base(Trigger) = trigger_secret : "Trigger: Secret" +[ + sounds(choices) : "Sound style" : 1 = + [ + 0 : "None" + 1 : "Secret sound" + 2 : "Beep beep" + 3 : "Large switch" + 4 : "Set message to text string" + ] + spawnflags(flags) = [ 1: "Entity only" : 0 ] +] + +@SolidClass base(Target, Targetname) = trigger_teleport : "Trigger teleport" +[ + spawnflags(Flags) = + [ + 1 : "Player only" : 0 + 2 : "Silent" : 0 + ] + onlymonster(choices) : "Limited to monsters?" : 0 = + [ + 0 : "No" + 1 : "Yes" + ] + notelefrag(choices) : "Wait instead of telefrag?" : 0 = + [ + 0 : "No" + 1 : "Yes" + ] + state(choices) : "Disable momentum" : 0 = + [ + 0 : "No" + 1 : "Yes" + ] +] + +// need updates: + +@SolidClass = 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 = trigger_monsterjump : "Trigger monster jump" +[ + speed(integer) : "Jump Speed" : 200 + height(integer) : "Jump Height" : 200 +] +@SolidClass base(trigger_monsterjump) = trigger_drolejump : "Trigger drolejump"[] + +@PointClass base(AllTargets) = trigger_counter : "Trigger counter" +[ + spawnflags(flags) = + [ + 1: "No Message" : 0 + 2: "Broadcast message" : 0 + ] + count(integer) : "Count before activation" : 2 +] +@SolidClass = trigger_push : "Trigger player push" +[ + spawnflags(flags) = [ 1: "Once Only" : 0 ] + speed(integer) : "Speed of push" : 1000 + noise(string) : "Sound while pushing" +] +@SolidClass base(Targetname, Deathtype) = trigger_hurt : "Trigger player hurt" +[ + dmg(integer) : "Damage" : 5 + wait(string) : "Frequency of damage" : "0.2" + message(string) : "Message" + cnt(integer) : "Count before deactivated" +] +@SolidClass base(Target) = trigger_damagethreshold : "Trigger damagethreshold" +[ + health(integer) : "Health" + spawnflags(flags) = + [ + 1: "Multi Use" : 0 + 2: "Invisible" : 0 + ] +] +@SolidClass = trigger_setgravity : "Trigger setgravity" +[ + gravity(integer) : "Gravity" +] + +@SolidClass base(Deathtype) = trigger_void : "Trigger void"[] + +@SolidClass = trigger_ladder : "Trigger ladder" +[ + noise(string) : "Climbing noise" + noise1(string) : "Attach noise" +] + +// Rotating entities + +@PointClass base(Targetname) = info_rotate : "Info rotate" +[] + +@SolidClass = rotate_object : "Visible rotating object" +[ + target(target_destination) : "Target (an info_rotate)" + targetname(target_source) : "Name (for controller)" +] + +@PointClass base(Targetname) = func_rotate_entity : "Simple rotating entity controller" +[ + target(target_destination) : "Target (a rotate_object)" + rotate(string) : "Rotate speed (x y z)" + speed(string) : "Acceleration time" + spawnflags(flags) = + [ + 1: "Toggle" : 0 + 2: "Starts On" : 0 + ] + +] + +@PointClass base(Targetname) = func_rotate_door : "Rotating door controller" +[ + target(target_destination) : "Target (the rotate_object/movewalls)" + rotate(string) : "Rotate axes (x y z)" + angles(string) : "Rotate distance" + speed(string) : "Acceleration time" + sounds(choices) : "Sounds" : 3 = + [ + 1: "Medieval" + 2: "Metal" + 3: "Base" + ] + spawnflags(flags) = + [ + 1: "Stay open" : 0 + ] + +] + +@SolidClass = func_movewall : "Func movewall" +[ + targetname(target_source) : "Name (to match rotate_object)" + spawnflags(flags) = + [ + 1: "Visible" : 0 + 2: "Damage on touch" : 0 + 4: "Non-solid" : 0 + ] +] + +@PointClass base(Targetname) = path_rotate : "Rotate train path" +[ + spawnflags(flags) = + [ + 1: "Rotation" : 0 + 2: "Angles" : 0 + 4: "Stop" : 0 + 8: "Stop rotate" : 0 + 16: "Damage" : 0 + 32: "Speed sets movetime" : 0 + 64: "Set damage" : 0 + ] + target(target_destination) : "Next path_rotate" + noise(string) : "Stop sound" + noise1(string) : "Start sound" + event(target_source) : "Event to trigger" + dmg(integer) : "Set train damage(set spawnflag too)" + rotate(string) : "Set rotate for next motion" + speed(choices) : "Speed(or movetime) for next motion" : 0 = + [ + -1 : "jumps to next waypoints" + ] + message(string) : "Message" + angles(string) : "Desired angle at this point" + wait(integer) : "Wait" : 0 +] + +@PointClass base(Targetname) = func_rotate_train : "Rotating train controller" +[ + target(target_destination) : "Target (the rotate_object/movewalls)" + path(target_destination) : "First path entity" + speed(string) : "Initial speed" + dmg(string) : "Initial damage" + sounds(choices) : "Sound" : 1 = + [ + 0: "None" + 1: "Ratchet Metal" + ] + spawnflags(flags) = + [ + 1: "Stay open" : 0 + ] + +] + + +//point versions +@PointClass base(func_door) = func_door_point : "Basic door" [] +@PointClass base(func_door_secret) = func_door_secret_point : "Triggered door" [] +@PointClass base(func_breakable) = func_breakable_point : "Breakable object"[] +@PointClass base(func_wall) = func_wall_point : "Wall"[] +@PointClass base(func_button) = func_button_point : "Button" [] +@PointClass base(func_train) = func_train_point : "Moving platform" [] +@PointClass base(func_plat) = func_plat_point : "Elevator" [] +@PointClass base(func_episodegate) = func_episodegate_point : "Episode Gate" [] +@PointClass base(func_bossgate) = func_bossgate_point : "Boss gate"[] +@PointClass base(trigger_changelevel) = trigger_changelevel_point : "Trigger: Change level"[] +@PointClass base(trigger_once) = trigger_once_point : "Trigger: Activate once"[] +@PointClass base(trigger_multiple) = trigger_multiple_point : "Trigger: Activate multiple"[] +@PointClass base(trigger_onlyregistered) = trigger_onlyregistered_point : "Trigger: Registered only"[] +@PointClass base(trigger_secret) = trigger_secret_point : "Trigger: Secret" [] +@PointClass base(trigger_teleport) = trigger_teleport_point : "Trigger teleport" [] +@PointClass base(trigger_setskill) = trigger_setskill_point : "Trigger set skill" [] +@PointClass base(trigger_relay) = trigger_relay_point : "Trigger relay"[] +@PointClass base(trigger_monsterjump) = trigger_monsterjump_point : "Trigger monster jump" [] +@PointClass base(trigger_counter) = trigger_counter_point : "Trigger counter" [] +@PointClass base(trigger_push) = trigger_push_point : "Trigger player push"[] +@PointClass base(trigger_hurt) = trigger_hurt_point : "Trigger player hurt" [] +@PointClass base(trigger_damagethreshold) = trigger_damagethreshold_point : "Trigger damagethreshold"[] +@PointClass base(trigger_drolejump) = trigger_drolejump_point : "Trigger drolejump"[] +@PointClass base(trigger_setgravity) = trigger_setgravity_point : "Trigger setgravity" [] +@PointClass base(trigger_void) = trigger_void_point : "Trigger void"[] +@PointClass base(trigger_ladder) = trigger_ladder_point : "Trigger ladder"[] +@PointClass base(func_door_button) = func_door_button_point : "Door-mounted Button"[] +@PointClass base(func_togglewall) = func_togglewall_point : "Toggleable wall" [] +@PointClass base(rotate_object) = rotate_object_point : "Visible rotating object" [] +@PointClass base(func_movewall) = func_movewall_point : "Func movewall" [] \ No newline at end of file diff --git a/tools/trenchbroom/games/Quake/Rubicon2.def b/tools/trenchbroom/games/Quake/Rubicon2.def new file mode 100644 index 0000000..6a2b60e --- /dev/null +++ b/tools/trenchbroom/games/Quake/Rubicon2.def @@ -0,0 +1,1438 @@ +/*QUAKED weapon_axe (0 .5 .8) (-16 -16 0) (16 16 32) +{ model(":progs/g_axe.mdl"); } +Axe. +*/ +/*QUAKED weapon_shotgun (0 .5 .8) (-16 -16 0) (16 16 32) +{ model(":progs/g_shotgn.mdl"); } +Shotgun. +*/ +/*QUAKED func_breakable (0 .5 .8) ? NO_MONSTERS +A visible object that can be destroyed by shooting it. If it has a targetname, it will not be directly damageable. + +NO_MONSTERS: object ignores damage from monsters + +"health" Default 20 + +"cnt" number of pieces of debris to spawn. default 6. + +"style" The style of the debris: +0 = green metal (default) +1 = red metal +2 = concrete +*/ +/*QUAKED func_explobox (0 .5 .8) ? START_OFF +An exploding brush entity. Works just like misc_explobox. + +Keys: + +"health" Default 20 + +"dmg" default 100 + +*/ +/*QUAKED func_laser (0 .5 .8) ? START_OFF LASER_SOLID +A togglable laser, hurts to touch, can be used to block players + +START_OFF: Laser starts off. + +LASER_SOLID: Laser blocks movement while turned on. + +Keys: + +"dmg" damage to do on touch. default 1 + +"alpha" approximate alpha you want the laser drawn at. default 0.5. alpha will vary by 20% of this value. + +"message" message to display when activated + +"message2" message to display when deactivated + +*/ +/*QUAKED func_turret (0 .5 .8) ? START_OFF +A rotating laser shooter that aims at the player in any horizontal direction. Has a capped rotation speed based on skill setting. When triggered, toggles between active and inactive states + +START_OFF spawns in the inactive state + +place in the level in the active/attacking position for proper lighting. + +"movedir" the offset from active position to the initial START_OFF position +"movedir2" the offset from the active position to the deactivated position (after being previously active) +"height" the position that laser originates, measured up from the very bottom of the model +"angle" determines the initial turret direction (horizontal directions only) +"speed" speed when moving to a new position +"sounds" sounds to use when moving to a new position +0) no sound +1) stone +2) base +3) stone chain +4) screechy metal +*/ +/*QUAKED item_circuitboard (0 .5 .8) (-16 -16 -24) (16 16 32) +collectible circuit board thing +*/ +/*QUAKED light_fixture1 (0 1 0) (-8 -8 -8) (8 8 24) +{ + model(":progs/fixture1.mdl"); +} +wall-mounted light fixture. +Default light value is 300 +Default style is 0 + +Keys: +"angle2" is the angle the model should be facing; set it to face away from the wall +*/ +/*QUAKED light_beacon (0 1 0) (-8 -8 -36) (8 8 8) BLINKING +{ + model(":progs/beacon.mdl"); +} +floor-mounted flashing red beacon +Default light value is 300 +Default style is 0 + +Flags: +"Blinking" if you want the beacon to blink (Set style to "16" to match the skin animation.) + +Keys: +"angle2" is the angle the model should be facing; set it to face away from the wall +*/ +/*QUAKED misc_flag (1 0 0) (-8 -8 -8) (8 8 8) NOT_ANIMATED BIG +{ + model(":progs/flag.mdl"); +} +A hanging banner, gently waving in the wind. Normal dimensions: 64 wide by 144 long. + +NOT_ANIMATED: Banner is not animated. + +BIG: Banner is twice as big: 128 wide by 288 long. +*/ +/*QUAKED misc_sparks (0 .5 .8) (-8 -8 -8) (8 8 8) START_OFF SPARKS_BLUE SPARKS_PALE +Produces a burst of yellow sparks at random intervals. If targeted, it will toggle between on or off. If it targets a light, that light will flash allong with each burst of sparks. Note: targeted lights should be set to START_OFF. + +SPARKS_BLUE: sparks are blue in color + +SPARKS_PALE: sparks are pale yellow in color + +Keys: + +"wait" is the average delay between bursts (variance is 1/2 wait). Default is 2. + +"cnt" is the average number of sparks in a burst (variance is 1/4 cnt). Default is 15. + +"sounds" +0) no sound +1) sparks +*/ +/*QUAKED misc_smoke (0 .5 .8) (-8 -8 -8) (8 8 8) START_OFF +Produces a jet of smoke/steam. If targeted, it will toggle between on or off. + +Keys: + +"wait" is the delay between puffs. Default is 0.1 + +"movedir" is a vector representing the initial velocity in X Y Z values. Default is "0 0 250" (up) + +"movedir2" is a vector representing the wind in X Y Z values. Default is "0 0 0" + +"dmg" is the amount of damage each puff gives on contact. Default is 0 + +"sounds" +0) no sound +1) steam hiss +*/ +/*QUAKED misc_splash (0 .5 .8) (-8 -8 -8) (8 8 8) +Produces a continuous particle splash for waterfalls + +"color" color of particles. 0 through 15, corresponds to a row of the quake palette. (default 0) + +"movedir" average movement vector of particles (default 0 0 4) + +"wait" time between particle generation cycles. (default 0.1) + +"volume" density of particles. (default 10) +*/ +/*QUAKED trigger_ladder (.5 .5 .5) ? +invisible ladder entity. when player is touching this entity, he can climb by pushing 'jump' + +Keys: + +"angle" the direction player must be facing to climb ladder +*/ +/*QUAKED monster_centurion (1 0 0) (-32 -32 -24) (32 32 64) AMBUSH x x x x x SPAWN_TRIGGERED SPAWN_SILENT +{ model(":progs/cent.mdl"); } +Centurion, 150 health points. + +AMBUSH: monster will only wake up on really seeing the player, not another monster getting angry. +*/ +/*QUAKED monster_dreadnaught (1 0 0) (-16 -16 -24) (16 16 40) AMBUSH x x x x x SPAWN_TRIGGERED SPAWN_SILENT +{ model(":progs/dread.mdl"); } +Dreadnaught, 150 health points. + +AMBUSH: dreadnaught will only wake up on really seeing the player, not another monster getting angry. +*/ +/*QUAKED monster_floyd (1 0 0) (-32 -32 -24) (32 32 64) AMBUSH ROLLING ASLEEP x x x SPAWN_TRIGGERED SPAWN_SILENT +{ model({ "path": ":progs/floyd.mdl", "skin": 0, "frame": 1 }); } +Automaton, 200 health points. + +AMBUSH: floyd will only wake up on really seeing the player, not another monster getting angry. + +ROLLING: floyd is on his back and helpless. explodes after taking 75 damage. + +ASLEEP: floyd will not respond to anything unless he is shot or his targetname is triggered. +*/ +/*QUAKED ambient_general (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +Plays any looped sound + +Keys: + +"noise" is the wav file to play + +"volume" default 0.5 + +"speed" attenuation, default 3 +*/ +/*QUAKED info_rotate (0 0.5 0) (-4 -4 -4) (4 4 4) +Used as the point of rotation for rotatable objects. +*/ +/*QUAKED func_movewall (0 .5 .8) ? VISIBLE TOUCH NONBLOCKING +Used to emulate collision on rotating objects. + +VISIBLE causes brush to be displayed. + +TOUCH specifies whether to cause damage when touched by player. + +NONBLOCKING makes the brush non-solid. This is useless if VISIBLE is set. + +"dmg" specifies the damage to cause when touched or blocked. +*/ +/*QUAKED func_rotate_door (0 .5 .8) (-8 -8 -8) (8 8 8) STAYOPEN +Creates a door that rotates between two positions around a point of +rotation each time it's triggered. + +STAYOPEN tells the door to reopen after closing. This prevents a trigger- +once door from closing again when it's blocked. + +"dmg" specifies the damage to cause when blocked. Defaults to 2. Negative numbers indicate no damage. +"speed" specifies how the time it takes to rotate + +"sounds" +1) medieval (default) +2) metal +3) base +4) screechy metal +*/ +/*QUAKED func_rotate_entity (0 .5 .8) (-8 -8 -8) (8 8 8) TOGGLE START_ON +Creates an entity that continually rotates. Can be toggled on and +off if targeted. + +TOGGLE = allows the rotation to be toggled on/off + +START_ON = wether the entity is spinning when spawned. If TOGGLE is 0, entity can be turned on, but not off. + +If "deathtype" is set with a string, this is the message that will appear when a player is killed by the train. + +"rotate" is the rate to rotate. +"target" is the center of rotation. +"speed" is how long the entity takes to go from standing still to full speed and vice-versa. +*/ +/*QUAKED func_rotate_train (0 .5 .8) (-8 -8 -8) (8 8 8) +In path_rotate, set speed to be the new speed of the train after it reaches +the path change. If speed is -1, the train will warp directly to the next +path change after the specified wait time. If MOVETIME is set on the +path_rotate, the train to interprets "speed" as the length of time to +take moving from one corner to another. + +"noise" contains the name of the sound to play when train stops. +"noise1" contains the name of the sound to play when train moves. +Both "noise" and "noise1" defaults depend upon "sounds" variable and +can be overridden by the "noise" and "noise1" variable in path_rotate. + +Also in path_rotate, if STOP is set, the train will wait until it is +retriggered before moving on to the next goal. + +Trains are moving platforms that players can ride. +"path" specifies the first path_rotate and is the starting position. +If the train is the target of a button or trigger, it will not begin moving until activated. +The func_rotate_train entity is the center of rotation of all objects targeted by it. + +If "deathtype" is set with a string, this is the message that will appear when a player is killed by the train. + +speed default 100 +dmg default 0 +sounds +1) ratchet metal +*/ +/*QUAKED path_rotate (0.5 0.3 0) (-8 -8 -8) (8 8 8) ROTATION ANGLES STOP NO_ROTATE DAMAGE MOVETIME SET_DAMAGE + Path for rotate_train. + + ROTATION tells train to rotate at rate specified by "rotate". Use '0 0 0' to stop rotation. + + ANGLES tells train to rotate to the angles specified by "angles" while traveling to this path_rotate. Use values < 0 or > 360 to guarantee that it turns in a certain direction. Having this flag set automatically clears any rotation. + + STOP tells the train to stop and wait to be retriggered. + + NO_ROTATE tells the train to stop rotating when waiting to be triggered. + + DAMAGE tells the train to cause damage based on "dmg". + + MOVETIME tells the train to interpret "speed" as the length of time to take moving from one corner to another. + + SET_DAMAGE tells the train to set all targets damage to "dmg" + + "noise" contains the name of the sound to play when train stops. + "noise1" contains the name of the sound to play when train moves. + "event" is a target to trigger when train arrives at path_rotate. +*/ +/*QUAKED rotate_object (0 .5 .8) ? +This defines an object to be rotated. Used as the target of func_rotate_door. +*/ + + +/*QUAKED air_bubbles (0 .5 .8) (-8 -8 -8) (8 8 8) +Air bubbles. They disappear +in Deathmatch. +*/ +/*QUAKED ambient_light_buzz (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +Buzzing light. Sound. +*/ +/*QUAKED ambient_drip (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +Dripping sound. +*/ +/*QUAKED ambient_drone (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +Drone sound. +*/ +/*QUAKED ambient_comp_hum (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +Computer sound. +*/ +/*QUAKED ambient_flouro_buzz (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +Fluorescent light sound. +*/ +/*QUAKED ambient_suck_wind (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +Wind sound. +*/ +/*QUAKED ambient_swamp1 (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +Swamp sound 1. +*/ +/*QUAKED ambient_swamp2 (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +Swamp sound 2. +*/ +/*QUAKED ambient_thunder (0.3 0.1 0.6) (-10 -10 -8) (10 10 8) +Thunder sound. +*/ +/*QUAKED event_lightning (0 1 1) (-16 -16 -16) (16 16 16) +Just for boss level. Used for +killing Cthon. +*/ +/*QUAKED func_bossgate (0 .5 .8) ? +This bmodel appears unless players +have all of the episode sigils. +Used to close the floor in start.map +(stairs to Shub). +*/ +/*QUAKED func_button (0 .5 .8) ? +When a button is touched, it moves +some distance in the direction of +it's angle, triggers all of it's targets, +waits some time, then returns to +it's original position where it can be +triggered again. + +Keys: +"angle" + determines the opening direction +"target" + all entities with a matching + targetname will be used +"killtarget" + kills matching targets when fired +"speed" + default is 40 +"delay" + waits # seconds before firing +"wait" + default is 1 (-1 = never return) +"lip" + override the default 4 pixel lip + remaining at end of move +"health" + if set, the button must be killed + instead of touched +"message" + centerprints message to activator +"sounds" + 0 = steam metal + 1 = wooden clunk + 2 = metallic click + 3 = in-out +*/ +/*QUAKED func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE +If two doors touch, they are +assumed to be connected and +operate as a unit. + +Key doors are always wait -1. + +Flags: +"start_open" + causes the door to move to its + destination and operate in + reverse. used to close areas + when triggered. + the entity will be lighted in + closed postion, but spawned + in the open position. +"x" + this flag has been removed +"door_dont_link" + even if doors touch they won't + be treated as a unit. +"gold_key" + you need the gold key to open + this door (check worldspawn!) +"silver_key" + you need the silver key to + open this door (worldspawn!) +"toggle" + causes the door to wait in both + the start and end states for a + trigger event + +Keys: +"message" + is printed when the door is touched + if it is a trigger door and it hasn't + been fired yet +"angle" + determines the opening direction +"targetname" + if set, no touch field will be + spawned and a remote button or + trigger field activates the door. +"target" + all matching entities will be used +"killtarget" + all matching entities will be + removed when fired +"health" + if set, door must be shot open +"speed" + movement speed (100 default) +"wait" + wait before returning (3 is default, + -1 = never return) +"delay" + waits # seconds before firing + matching targets +"lip" + lip remaining at end of move + 8 is default +"dmg" + damage to inflict when blocked + 2 is default +"sounds" + 0 = no sound + 1 = stone + 2 = base + 3 = stone chain + 4 = screechy metal +*/ +/*QUAKED func_door_secret (0 .5 .8) ? OPEN_ONCE 1ST_LEFT 1ST_DOWN NO_SHOOT ALWAYS_SHOOT +Basic secret door. Slides back, +then to the side. Angle determines +direction. + +Flags: +"open_once" + stays open when triggered +"1st_left" + 1st move is left of arrow +"1st_down" + 1st move is down from arrow +"no_shoot" + only opened by trigger +"always_shoot" + even if targeted, keep shootable + +Keys: +"target" + all matching targets will be used +"killtarget" + all matching entities will be + removed +"wait" + # of seconds before coming back +"delay" + waits # seconds before firing + its targets +"t_width" + override Width to move back + (or height if going down) +"t_length" + override Length to move sideways +"dmg" + damage to inflict when blocked + (2 default) +"message" + prints message when touched + +If a secret door has a targetname, +it will only be opened by it's button +or trigger, not by damage. + +"sounds" + 1 = medieval + 2 = metal + 3 = base +*/ +/*QUAKED func_episodegate (0 .5 .8) ? E1 E2 E3 E4 +This bmodel will appear if the +episode has already been +completed, so players can't +reenter it. +*/ +/*QUAKED func_illusionary (0 .5 .8) ? +A simple entity that looks solid +but lets you walk through it. +Does not block light. +*/ +/*QUAKED func_wall (0 .5 .8) ? +This is just a solid wall if not +inhibitted. + +Changes its texture(s) to alternate +ones (e.g. basebtn), if targetted. +*/ +/*QUAKED func_train (0 .5 .8) ? RETRIGGER +Trains are moving platforms that +players can ride. The target's origin +specifies the min point of the train +at each corner. The train spawns +at the first target it is pointing at. + +Use path_corner as targets. + +To stop a train entity, make the +the last path_corner Wait -1. + +If the train itself is the target of a +button or trigger, it will not begin +moving until activated. + +Flags: + +RETRIGGER: stop at each path_corner and don't resume until triggered again (ignores wait time) + +Keys: +"speed" + moving speed, default is 100 +"dmg" + damage, default is 2 +"sounds" + 1 = ratchet metal + 2 = base +*/ +/*QUAKED func_plat (0 .5 .8) ? PLAT_LOW_TRIGGER +Plats are always drawn in the +extended position, so they will +light correctly. + +If the plat is the target of another +trigger or button, it will start out +disabled in the extended position +until it is triggered, when it will lower +and become a normal plat. + +Flags: + "plat_low_trigger" + plat will only be triggered when in + lowered position + +Keys: +"speed" + moving speed, default is 150 +"height" + determines the amount the plat + moves, instead of being implicitly + determined by the model's height. +"sounds" + 1 = base fast + 2 = chain slow +*/ +/*QUAKED func_dm_only (.0 .0 1.0) ? +A teleporter that only appears in +deathmatch. +*/ +/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4) +Invisible entity. Used as a positional +target for spotlights, etc. +Removes itself. +*/ +/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4) +Invisible entity. Used as a positional +target for lightning. +*/ +/*QUAKED info_intermission (1 0.5 0.5) (-16 -16 -16) (16 16 16) +This is the camera point for the +intermission. Use mangle instead +of angle, so you can set pitch or roll +as well as yaw. 'pitch yaw roll' +Quake does a random pick if more +than one exists. +If no info_intermission entity is set, +Quake uses the player start. + +Keys: +"mangle" + set 'pitch yaw roll' +*/ +/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 24) +{ model(":progs/player.mdl"); } +The normal starting point for a level. +Only one is allowed. + +Keys: +"angle" + viewing angle when spawning +*/ +/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 24) +{ model(":progs/player.mdl"); } +Potential spawning position(s) for +deathmatch games. + +Keys: +"angle" + viewing angle when spawning +*/ +/*QUAKED info_player_coop (1 0 1) (-16 -16 -24) (16 16 24) +{ model(":progs/player.mdl"); } +Potential spawning position(s) for +coop games. + +Keys: +"angle" + viewing angle when spawning +*/ +/*QUAKED info_player_start2 (1 0 0) (-16 -16 -24) (16 16 24) +{ model(":progs/player.mdl"); } +Only used on start map for the +return point from an episode. + +Keys: +"angle" + viewing angle when spawning +*/ +/*QUAKED info_teleport_destination (0.5 0.5 0.5) (-8 -8 -8) (8 8 32) +This is the destination marker for a +teleporter. + +Keys: +"targetname" + value used by teleporter +"angle" + new view angle after teleporting +*/ +/*QUAKED item_cells (0 .5 .8) (0 0 0) (32 32 32) BIG +{ +model({{ spawnflags == 1 -> ":maps/b_batt1.bsp", ":maps/b_batt0.bsp" }}); +} +6 ammo points (cells) for the +Thunderbolt (Lightning). + +Flags: +"big" + gives 12 instead of 6 +*/ +/*QUAKED item_rockets (0 .5 .8) (0 0 0) (32 32 32) BIG +{ +model({{ spawnflags == 1 -> ":maps/b_rock1.bsp", ":maps/b_rock0.bsp" }}); +} +5 ammo points (rockets) for the +Rocket/Grenade Launcher. + +Flags: +"big" + gives 10 instead of 5 +*/ +/*QUAKED item_shells (0 .5 .8) (0 0 0) (32 32 32) BIG +{ +model({{ spawnflags == 1 -> ":maps/b_shell1.bsp", ":maps/b_shell0.bsp" }}); +} +20 shells for both Shotgun and +SuperShotgun. + +Flags: +"big" + gives 40 instead of 20 +*/ +/*QUAKED item_spikes (0 .5 .8) (0 0 0) (32 32 32) BIG +{ +model({{ spawnflags == 1 -> ":maps/b_nail1.bsp", ":maps/b_nail0.bsp" }}); +} +25 ammo points (spikes) for +Perforator and Super Perforator. + +Flags: +"big" + gives 50 instead of 25 +*/ +/*QUAKED item_health (.3 .3 1) (0 0 0) (32 32 32) ROTTEN MEGAHEALTH +{ + model({{ spawnflags == 2 -> ":maps/b_bh100.bsp", spawnflags == 1 -> ":maps/b_bh10.bsp", ":maps/b_bh25.bsp" }}); +} +Health box. Normally gives 25 points. + +Flags: +"rotten" + gives 5-10 points +"megahealth" + will add 100 health, then rot you + down to your maximum health limit, + one point per second +*/ +/*QUAKED item_artifact_envirosuit (0 .5 .8) (-16 -16 -24) (16 16 32) +{ model(":progs/suit.mdl"); } +Player takes no damage from water +or slime for 30 seconds. +*/ +/*QUAKED item_artifact_super_damage (0.5 0.0 0.0) (-8 -8 -8) (8 8 24) +{ model(":progs/quaddama.mdl"); } +Quad Damage. Lasts 30 seconds. +*/ +/*QUAKED item_artifact_invulnerability (0 .5 .8) (-16 -16 -24) (16 16 32) +{ model(":progs/invulner.mdl"); } +Player is invulnerable for 30 seconds. +*/ +/*QUAKED item_artifact_invisibility (0 .5 .8) (-16 -16 -24) (16 16 32) +{ model(":progs/invisibl.mdl"); } +Player is invisible for 30 seconds. +*/ +/*QUAKED item_armorInv (0 .5 .8) (-16 -16 0) (16 16 32) +{ model({ "path": ":progs/armor.mdl", "skin": 2 }); } +Red armor, gives 200 armor points. +*/ +/*QUAKED item_armor2 (0 .5 .8) (-16 -16 0) (16 16 32) +{ model({ "path": ":progs/armor.mdl", "skin": 1 }); } +Yellow armor, gives 150 points. +*/ +/*QUAKED item_armor1 (0 .5 .8) (-16 -16 0) (16 16 32) +{ model(":progs/armor.mdl"); } +Green armor, gives 100 points. +*/ +/*QUAKED item_key1 (0 .5 .8) (-16 -16 -24) (16 16 32) +{ model(":progs/w_s_key.mdl"); } +SILVER key. + +In order for keys to work you +MUST set your maps worldtype +(see worldspawn). +*/ +/*QUAKED item_key2 (0 .5 .8) (-16 -16 -24) (16 16 32) +{ model(":progs/w_g_key.mdl"); } +GOLD key. + +In order for keys to work you +MUST set your maps worldtype +(see worldspawn). +*/ +/*QUAKED item_sigil (0 .5 .8) (-16 -16 -24) (16 16 32) E1 E2 E3 E4 +{ + model(":progs/end1.mdl"); + default("spawnflags","1"); +} +End of episode sigil. + +Flags: + sets episode +*/ +/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) START_OFF +~ 3 +Non-displayed light. If targeted, it +will toggle between on or off. + +Flags: +"start_off" + starts off until triggered + +Keys: +"light" + sets brightness, 300 is default +"style" + 0 = normal + 1 = flicker (first variety) + 2 = slow strong pulse + 3 = candle (first variety) + 4 = fast strobe + 5 = gentle pulse + 6 = flicker (second variety) + 7 = candle (second variety) + 8 = candle (third variety) + 9 = slow strobe + 10 = flourescent flicker + 11 = slow pulse, not fading to black + + styles 32-62 are assigned by the + light program for switchable lights + 0 is default +"target" + makes this light a spot light. This should + entity to be an entity for the spot line to + point at (usually a info_null) +"angle" + angle of the cone of the light from the spotlight +*/ +/*QUAKED light_torch_small_walltorch (0 .5 0) (-10 -10 -20) (10 10 20) +{ +model(":progs/flame.mdl"); +} +~ 3 +Short wall torch. + +Keys: +"light" + sets brightness, 200 is default +"style" + 0 = normal + 1 = flicker (first variety) + 2 = slow strong pulse + 3 = candle (first variety) + 4 = fast strobe + 5 = gentle pulse + 6 = flicker (second variety) + 7 = candle (second variety) + 8 = candle (third variety) + 9 = slow strobe + 10 = flourescent flicker + 11 = slow pulse, not fading to black + + styles 32-62 are assigned by the + light program for switchable lights + 0 is default +*/ +/*QUAKED light_flame_large_yellow (0 1 0) (-10 -10 -12) (12 12 18) +{ +model(":progs/flame2.mdl"); +} +~ 3 +Large yellow flames. + +Keys: +"light" + sets brightness +*/ +/*QUAKED light_flame_small_yellow (0 1 0) (-8 -8 -8) (8 8 8) START_OFF +{ +model(":progs/flame2.mdl"); +} +~ 3 +Small yellow flames. + +Flags: +"start_off" + starts off until triggered + +Keys: +"light" + sets brightness +*/ +/*QUAKED light_flame_small_white (0 1 0) (-10 -10 -40) (10 10 40) START_OFF +{ +model(":progs/flame2.mdl"); +} +~ 3 +Small white flames. + +Flags: +"start_off" + starts off until triggered + +Keys: +"light" + sets brightness +*/ +/*QUAKED light_fluoro (0 1 0) (-8 -8 -8) (8 8 8) START_OFF +~ 3 +Non-displayed light. Makes steady +fluorescent humming sound. + +Flags: +"start_off" + starts off until triggered + +Keys: +"light" + sets brightness, 300 is default +"style" + 0 = normal + 1 = flicker (first variety) + 2 = slow strong pulse + 3 = candle (first variety) + 4 = fast strobe + 5 = gentle pulse + 6 = flicker (second variety) + 7 = candle (second variety) + 8 = candle (third variety) + 9 = slow strobe + 10 = flourescent flicker + 11 = slow pulse, not fading to black + + styles 32-62 are assigned by the + light program for switchable lights + 0 is default +*/ +/*QUAKED light_fluorospark (0 1 0) (-8 -8 -8) (8 8 8) +~ 3 +Non-displayed light. Makes +sparking, broken fluorescent +sound. + +Keys: +"light" + sets brightness, 300 is default +"style" + 0 = normal + 1 = flicker (first variety) + 2 = slow strong pulse + 3 = candle (first variety) + 4 = fast strobe + 5 = gentle pulse + 6 = flicker (second variety) + 7 = candle (second variety) + 8 = candle (third variety) + 9 = slow strobe + 10 = flourescent flicker + 11 = slow pulse, not fading to black + + styles 32-62 are assigned by the + light program for switchable lights + 10 is default +*/ +/*QUAKED light_globe (0 1 0) (-8 -8 -8) (8 8 8) +~ 3 +Sphere globe light (sprite). + +Keys: +"light" + sets brightness, 300 is default +"style" + 0 = normal + 1 = flicker (first variety) + 2 = slow strong pulse + 3 = candle (first variety) + 4 = fast strobe + 5 = gentle pulse + 6 = flicker (second variety) + 7 = candle (second variety) + 8 = candle (third variety) + 9 = slow strobe + 10 = flourescent flicker + 11 = slow pulse, not fading to black + + styles 32-62 are assigned by the + light program for switchable lights + 0 is default +*/ +/*QUAKED misc_noisemaker (1 0.5 0) (-10 -10 -10) (10 10 10) +For optimization testing, starts +a lot of sounds. Not very useful. +*/ +/*QUAKED monster_enforcer (1 0 0) (-16 -16 -24) (16 16 40) AMBUSH x x x x x SPAWN_TRIGGERED SPAWN_SILENT +{ model(":progs/enforcer.mdl"); } +Enforcer, 80 health points. + +Flags: +"ambush" + the monster will only wake up on + really seeing the player, not another + monster getting angry +*/ +/*QUAKED monster_hell_knight (1 0 0) (-16 -16 -24) (16 16 40) AMBUSH x x x x x SPAWN_TRIGGERED SPAWN_SILENT +{ model(":progs/hknight.mdl"); } +Hell Knight, 250 health points. + +Flags: +"ambush" + the monster will only wake up on + really seeing the player, not another + monster getting angry +*/ +/*QUAKED monster_army (1 0 0) (-16 -16 -24) (16 16 40) AMBUSH x x x x x SPAWN_TRIGGERED SPAWN_SILENT +{ model(":progs/soldier.mdl"); } +Grunt, 30 health points. + +Flags: +"ambush" + the monster will only wake up on + really seeing the player, not another + monster getting angry +*/ +/*QUAKED monster_dog (1 0 0) (-32 -32 -24) (32 32 40) AMBUSH x x x x x SPAWN_TRIGGERED SPAWN_SILENT +{ model(":progs/dog.mdl"); } +Dog (Rottweiler), 25 health points. + +Flags: +"ambush" + the monster will only wake up on + really seeing the player, not another + monster getting angry +*/ +/*QUAKED monster_ogre (1 0 0) (-32 -32 -24) (32 32 64) AMBUSH x x x x x SPAWN_TRIGGERED SPAWN_SILENT +{ model(":progs/ogre.mdl"); } +Ogre, 200 health points. + +Flags: +"ambush" + the monster will only wake up on + really seeing the player, not another + monster getting angry +*/ +/*QUAKED monster_knight (1 0 0) (-16 -16 -24) (16 16 40) AMBUSH x x x x x SPAWN_TRIGGERED SPAWN_SILENT +{ model(":progs/knight.mdl"); } +Knight, 75 health points. + +Flags: +"ambush" + the monster will only wake up on + really seeing the player, not another + monster getting angry +*/ +/*QUAKED monster_zombie (1 0 0) (-16 -16 -24) (16 16 32) CRUCIFIED AMBUSH x x x x SPAWN_TRIGGERED SPAWN_SILENT +{ model(":progs/zombie.mdl"); } +Zombie, 60 health points. +If crucified, stick the bounding +box 12 pixels back into a wall to +look right. + +Flags: +"crucified" + :-) +"ambush" + the monster will only wake up on + really seeing the player, not another + monster getting angry +*/ +/*QUAKED monster_wizard (1 0 0) (-16 -16 -24) (16 16 40) AMBUSH x x x x x SPAWN_TRIGGERED SPAWN_SILENT +{ model(":progs/wizard.mdl"); } +Scrag (Wizard), 80 health points. + +Flags: +"ambush" + the monster will only wake up on + really seeing the player, not another + monster getting angry +*/ +/*QUAKED monster_demon1 (1 0 0) (-32 -32 -24) (32 32 64) AMBUSH x x x x x SPAWN_TRIGGERED SPAWN_SILENT +{ model(":progs/demon.mdl"); } +Fiend (Demon), 300 health points. + +Flags: +"ambush" + the monster will only wake up on + really seeing the player, not another + monster getting angry +*/ +/*QUAKED monster_oldone (1 0 0) (-16 -16 -24) (16 16 32) +{ model(":progs/oldone.mdl"); } +Shub-Niggurath, 40000 health points. +Most likely killed by teleport frag. +*/ +/*QUAKED monster_shambler (1 0 0) (-32 -32 -24) (32 32 64) AMBUSH x x x x x SPAWN_TRIGGERED SPAWN_SILENT +{ model(":progs/shambler.mdl"); } +Shambler, 600 health points. +Rockets only have half damage +when hitting the Shambler. + +Flags: +"ambush" + the monster will only wake up on + really seeing the player, not another + monster getting angry +*/ +/*QUAKED monster_shalrath (1 0 0) (-32 -32 -24) (32 32 48) AMBUSH x x x x x SPAWN_TRIGGERED SPAWN_SILENT +{ model(":progs/shalrath.mdl"); } +Vore (Shalrath), 400 health points. + +Flags: +"ambush" + the monster will only wake up on + really seeing the player, not another + monster getting angry +*/ +/*QUAKED monster_boss (1 0 0) (-128 -128 -24) (128 128 256) +{ model(":progs/boss.mdl"); } +Cthon (Boss of Shareware Quake) +Only event_lightning can kill him. +*/ +/*QUAKED monster_tarbaby (1 0 0) (-16 -16 -24) (16 16 24) AMBUSH x x x x x SPAWN_TRIGGERED SPAWN_SILENT +{ model(":progs/tarbaby.mdl"); } +Spawn (Tarbaby), 80 health points. + +Flags: +"ambush" + the monster will only wake up on + really seeing the player, not another + monster getting angry +*/ +/*QUAKED monster_fish (1 0 0) (-16 -16 -24) (16 16 24) AMBUSH x x x x x SPAWN_TRIGGERED SPAWN_SILENT +{ model(":progs/fish.mdl"); } +Rotfish, 25 health points. + +Flags: +"ambush" + the monster will only wake up on + really seeing the player, not another + monster getting angry +*/ +/*QUAKED misc_teleporttrain (0 .5 .8) (-8 -8 -8) (8 8 8) +{ model(":progs/teleport.mdl"); } +This is used for the final boss. +Flying ball needed to teleport +kill Shub-Niggurath. +*/ +/*QUAKED misc_fireball (0 .5 .8) (-8 -8 -8) (8 8 8) +Lava Ball. + +Keys: +"speed" + speed of ball, default is 1000 + -- actually about 100 +*/ +/*QUAKED misc_explobox (0 .5 .8) (0 0 0) (32 32 64) +{ + model(":maps/b_explob.bsp"); +} +Exploding box. +*/ +/*QUAKED misc_explobox2 (0 .5 .8) (0 0 0) (32 32 64) +{ + model(":maps/b_exbox2.bsp"); +} +Smaller exploding box. +*/ +/*QUAKED noclass (0 0 0) (-8 -8 -8) (8 8 8) +Prints a warning message and its +position (to console) when spawned. +Removes itself after doing this. +*/ +/*QUAKED path_corner (0.5 0.3 0) (-8 -8 -8) (8 8 8) +Monsters will continue walking +towards the next target corner. +Also used by func_train. +*/ +/*QUAKED test_teleport (0 .5 .8) ? +Teleporter testing. For +testing only. Don't use it. +*/ +/*QUAKED test_fodder (0 .5 .8) ? +Beating guy? For testing +only. Never used in Quake. +Don't use it. +*/ +/*QUAKED trap_spikeshooter (0 .5 .8) (-8 -8 -8) (8 8 8) SUPERSPIKE LASER +When triggered, fires a spike in +the direction determined by angle. + +Flags: +"superspike" + fires large spikes +"laser" + fires laser + +Keys: +"angle" + angle to fire +*/ +/*QUAKED trap_shooter (0 .5 .8) (-8 -8 -8) (8 8 8) SUPERSPIKE LASER +Continuously fires spikes. + +Flags: +"superspike" + fires large spikes +"laser" + fires laser + +Keys: +"angle" + angle to fire +"wait" + time between spikes (1.0 default) +"nextthink" + delay before firing first spike, + so multiple shooters can be + stagered +*/ +/*QUAKED trigger_teleport (0.5 0.0 0.5) ? PLAYER_ONLY SILENT +Any object touching this will be +transported to the corresponding +info_teleport_destination entity. + +Flags: +"player_only" + only players will teleport +"silent" + silences teleporting +*/ +/*QUAKED trigger_changelevel (0.5 0.5 0.5) ? NO_INTERMISSION +When the player touches this, he +gets sent to the map listed in the +"map" variable. The view will go to +the info_intermission spot and +display stats. + +Keys: +"map" + set to name of next map + (e.g. e1m1) if no map is set, + the current map will be restartet + +Flags: +"no_intermission" + bypasses intermission screen +*/ +/*QUAKED trigger_setskill (0.5 0.0 0.5) ? +Sets skill level to the value of +"message". Only used on start +map. + +Keys: +"message" + sets skill level + 0 = easy + 1 = normal + 2 = hard + 3 = nightmare +*/ +/*QUAKED trigger_counter (0.5 0.0 0.5) (-8 -8 -8) (8 8 8) NOMESSAGE +Acts as an intermediary for an action +that takes multiple inputs. +If nomessage is not set, it will +print "1 more.. " etc when triggered +and "sequence complete" when +finished. After the counter has been +triggered "count" times, it will fire all +of it's targets and remove itself. + +It's a once-only trigger (i.e. Wait is +always -1). + +Flags: +"nomessage" + disables count display + +Keys: +"count" + number of triggers needed to fire + own target, default is 2 +"message" + prints message after completing + the sequence. if no delay is set, + this message overwrites standard + 'sequence completed' message. +"delay" + waits # seconds before firing + targets/writing message +"target" + targets to fire +"killtarget" + targets to remove when fired +*/ +/*QUAKED trigger_once (0.5 0.0 0.5) ? NOTOUCH +Variable sized trigger. Triggers +once, then removes itself. + +It's the same as trigger_multiple, but +Wait is always -1. + +Flags: +"notouch" + only triggered by other entities, not + by touching + +Keys: +"health" + button must be killed to activate +"angle" + the trigger will only fire when + someone is facing the direction of + the angle, use "360" for angle 0. +"sounds" + 1 = secret + 2 = beep beep + 3 = large switch +"message" + displayed text when fired +"delay" + delay before firing (after trigger) +"target" + targets to fire when fired +"killtarget" + targets to remove when fired +*/ +/*QUAKED trigger_multiple (0.5 0.0 0.5) ? NOTOUCH +Variable sized repeatable trigger. +Must be targeted at one or more +entities. + +Flags: +"notouch" + only triggered by other entities, not + by touching + +Keys: +"health" + button must be killed to activate +"angle" + the trigger will only fire when + someone is facing the direction of + the angle, use "360" for angle 0. +"sounds" + 1 = secret + 2 = beep beep + 3 = large switch +"message" + displayed text when fired +"delay" + delay before firing (after trigger) +"wait" + delay between triggerings + default is 0.2 +"target" + targets to fire when fired +"killtarget" + targets to remove when fired +*/ +/*QUAKED trigger_onlyregistered (0.5 0.0 0.5) ? +Only fires if playing the registered +version, otherwise prints the message. + +Keys: +"message" + message to print when playing + the shareware version. +*/ +/*QUAKED trigger_secret (0.5 0.0 0.5) ? +Secret counter trigger. + +Keys: +"message" + message to display when + triggered +"sounds" + 1 = secret + 2 = beep beep +"delay" + waits # seconds before displaying + message/firing targets +"target" + targets to fire when fired +"killtarget" + targets to remove when fired +*/ +/*QUAKED trigger_monsterjump (0.5 0.0 0.5) ? +Walking monsters that touch this +will jump in the direction of the +trigger's angle. + +Keys: +"angle" + angle towards the monster jumps +"speed" + the speed thrown forward + default is 200 +"height" + the speed thrown upwards + default is 200 +*/ +/*QUAKED trigger_relay (0.5 0.0 0.5) (-8 -8 -8) (8 8 8) +This fixed size trigger cannot be +touched, it can only be fired by +other events. + +Keys: +"killtarget" + removes target +"target" + fires target when triggered +"delay" + delay before firing (after trigger) +"message" + displayed when fired +*/ +/*QUAKED trigger_hurt (0.5 0.0 0.5) ? +Any object touching this will be hurt. + +Keys: +"dmg" + sets damage, default is 5 +*/ +/*QUAKED trigger_push (0.5 0.0 0.5) ? PUSH_ONCE +Pushes the player and Grenades. +Use this to create wind tunnels +and currents. + +Flags: +"push_once" + removes itself after firing + +Keys: +"speed" + speed of push, default is 1000 +"angle" + direction of push + (-2 is down, -1 up) +*/ +/*QUAKED viewthing (0 .5 .8) (-8 -8 -8) (8 8 8) +A model will be spawned at +the position of this entity. +(default = player) + +Just for debugging. +Don't use. + +Use the console commands +'viewmodel', 'viewframe', +'viewnext', 'viewprev' to +view frames of model. +*/ +/*QUAKED weapon_supershotgun (0 .5 .8) (-16 -16 0) (16 16 32) +{ model(":progs/g_shot.mdl"); } +SuperShotgun. +*/ +/*QUAKED weapon_nailgun (0 .5 .8) (-16 -16 0) (16 16 32) +{ model(":progs/g_nail.mdl"); } +Perforator (Nailgun). +*/ +/*QUAKED weapon_supernailgun (0 .5 .8) (-16 -16 0) (16 16 32) +{ model(":progs/g_nail2.mdl"); } +Super Perforator (Super +Nailgun). +*/ +/*QUAKED weapon_grenadelauncher (0 .5 .8) (-16 -16 0) (16 16 32) +{ model(":progs/g_rock.mdl"); } +Grenade Launcher. +*/ +/*QUAKED weapon_rocketlauncher (0 .5 .8) (-16 -16 0) (16 16 32) +{ model(":progs/g_rock2.mdl"); } +Rocket Launcher. +*/ +/*QUAKED weapon_lightning (0 .5 .8) (-16 -16 0) (16 16 32) +{ model(":progs/g_light.mdl"); } +Thunderbolt Cannon. +*/ +/*QUAKED worldspawn (0 0 0) ? +Only used for the world entity. +Should be only one per MAP. + +Keys: +"wad" + which graphics wad to use +"message" + sets the title of the map +"worldtype" + 0 = medieval + 1 = metal + 2 = base + MUST be set when using keys! +"sounds" + CD track to play +"light" + default light level +*/ diff --git a/tools/trenchbroom/games/Quake/Teamfortress.fgd b/tools/trenchbroom/games/Quake/Teamfortress.fgd new file mode 100644 index 0000000..491a615 --- /dev/null +++ b/tools/trenchbroom/games/Quake/Teamfortress.fgd @@ -0,0 +1,1070 @@ +// +// 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 + +// Modified by sort 5/28/2018. Merged with Fortress_edit.fgd. +// Visit: http://discord.megateamfortress.com + +// +// 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 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) = + 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) = 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 " [] + +// +// 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" [] + + + +// FORTRESS + + +// TEAM FORTRESS BASE CLASSES + +@BaseClass = TFDetectflags [ ] +@baseclass base (TFDetectflags) size(0 0 0, 24 24 24) color(255 128 0) = TfDClass +[ + netname(string) : "netname" +] +@baseclass size(0 0 0, 24 24 24) color(255 128 0) = TfClass +[ + netname(string) : "netname" +] + +// MEGA-TF AMBIENT ADDONS + +@PointClass = ambient_brook : "Stream or Brook (Mega)" [] +@PointClass = ambient_ice_moving : "Ice Moving (Mega)" [] +@PointClass = ambient_high_wind : "High wind sound (Mega)" [] +@PointClass = ambient_meadow : "Birdsong of Meadow (Mega)" [] +@PointClass = ambient_nightpond : "Crickets & Frogs (Mega)" [] +@PointClass = ambient_alert : "Star Trek Alert (Mega)" [] +@PointClass = ambient_onboard : "Onboard Engines (Mega)" [] +@PointClass = ambient_rocket_engine : "Near Rocket Engines (Mega)" [] +@PointClass = ambient_chant : "Mystical Chanting (Mega)" [] +@PointClass = ambient_unholy : "Unholy Kingdoms Map Music (Mega)" [] +@PointClass = ambient_ocean : "Soothing Ocean (Mega)" [] +@PointClass = ambient_eerie : "Cavern with Wind (Mega)" [] +@PointClass = ambient_lavapit : "Boiling Lava with Steam (Mega)" [] +@PointClass = ambient_peakwind : "Whistling Wind (Mega)" [] +@PointClass = ambient_flagflap : "Flag Whipping in Wind (Mega)" [] + +// INFO_TFDETECT + +@PointClass base(TfClass) = info_tfdetect : "TF Detection Entity" +[ + impulse(Flags) = + [ + 1 : "Class Skins" : 0 + 2 : "Class Persistence" : 0 + 4 : "Cheat Checking" : 0 + 8 : "Fortress Map" : 0 + 16 : "Respawn Delay" : 0 + 32 : "Respawn Delay" : 0 + 64 : "Auto Team" : 0 + 128 : "Individual Frags" : 0 + ] + message(string) : "Localcmds to send to server on start" + ammo_shells(integer) : "Max lives for player in Team 1." + ammo_nails(integer) : "Max lives for player in Team 2." + ammo_rockets(integer) : "Max lives for player in Team 3." + ammo_cells(integer) : "Max lives for player in Team 4." + ammo_medikit(integer) : "Max players allowed in Team 1." + ammo_detpack(integer) : "Max players allowed in Team 2." + maxammo_medikit(integer) : "Max players allowed in Team 3." + maxammo_detpack(integer) : "Max players allowed in Team 4." + maxammo_shells(integer) : "Bitfield. Restricted Classes Team 1" + maxammo_nails(integer) : "Bitfield. Restricted Classes Team 2" + maxammo_rockets(integer) : "Bitfield. Restricted Classes Team 3" + maxammo_cells(integer) : "Bitfield. Restricted Classes Team 4" + hook_out(choices) : "Grapple Hook Enabled?" : 0 = + [ + 0 : "Enabled" + 1 : "Disabled" + ] + display_item_status1(string) : "On FlagInfo, display this GoalItem status" + display_item_status2(string) : "On FlagInfo, display this GoalItem status" + display_item_status3(string) : "On FlagInfo, display this GoalItem status" + display_item_status4(string) : "On FlagInfo, display this GoalItem status" + team_str_home(string) : "Disp to owner if is at its origin." + team_str_moved(string) : "Disp to owner if is not at its origin." + team_str_carried(string) : "Disp to owner if being carried." + non_team_str_home(string) : "Disp to others if is at its origin." + non_team_str_moved(string) : "Disp to others if is not at its origin." + non_team_str_carried(string) : "Disp to others if is being carried." + team_broadcast(string) : "String that replaces the Team Menu." + non_team_broadcast(string) : "String that is the Map Help command." + noise1(string) : "Class Menu for Team 1." + noise2(string) : "Class Menu for Team 2." + noise3(string) : "Class Menu for Team 3." + noise4(string) : "Class Menu for Team 4." +] + +// INFO_TFGOAL + +@PointClass base(TfClass) = info_tfgoal : "TF Goal Entity" +[ +netname(string) : "The name of the Goal." +goal_no(integer) : "Unique ID number of this goal." +group_no(integer) : "ID Number of the goal group this goal belongs to." +owned_by(integer) : "The Team that own this entity." +goal_state(integer) : "Bitfield. The initial state." +mdl(string) : "The mdl used by this Goal if any." +skin(integer) : "The number of the skin on mdl." +goal_activation(integer) : "Bitfield. Activation criteria." +team_no(integer) : "AP must be of this team to activate." +items_allowed(integer) : "AP must have this goal item no" +has_item_from_group(integer) : "AP must have Item from group no" +playerclass(integer) : "Bitfield. Must be of this class(es)." +if_goal_is_active(integer) : "This Goal must be in ACTIVE state." +if_goal_is_inactive(integer) : "This Goal must be in INACTIVE state." +if_goal_is_removed(integer) : "This Goal must be in REMOVED state." +if_group_is_active(integer) : "All Goals in Group must be in ACTIVE." +if_group_is_inactive(integer) : "All Goals in Group must be in INACTIVE." +if_group_is_removed(integer) : "All Goals in Group must be in REMOVED." +if_item_has_moved(integer) : "This Item not moved or carried." +if_item_hasnt_moved(integer) : "This Item must be moved or carried." +else_goal(integer) : "If criteria fails, activate this goal no" +goal_min(string) : "Bounding box min for goal, def is -16 -16 -24" +goal_max(integer) : "Bounding box max for goal, def is 16 16 32" +// When this Goal is successfully activated up, the following variables may be executed +return_item_no(integer) : "Return this GoalItem if not carried" +broadcast(string) : "Message centerprinted to everyone else." +message(string) : "Message centerprinted to AP." +team_broadcast(string) : "Message centerprinted to teammates" +non_team_broadcast(string) : "Message centerprinted to other team" +owners_team_broadcast(string) : "Centerprinted to all owning teammates" +netname_broadcast(string) : "_____ activated this goal.\n" +netname_team_broadcast(string) : "_____ activated your teams goal.\n" +netname_non_team_broadcast(string) : "____ took an enemy flag!\n" +netname_owners_team_broadcast(string) : "____ took your flag!\n" +deathtype(string) : "___ was killed by this goal!\n" +target(string) : "Activate goal with this targetname" +killtarget(string) : "Remove goal with this targetname" +ex_skill_min(integer) : "Skill Minimum" +ex_skill_max(integer) : "Skill Maximum" +goal_effects(integer) : "Bitfield. See TFEntRef" +maxammo_shells(integer) : "All members of this team are affected." +maxammo_nails(integer) : "All members not of this team are affected." +t_length(integer) : "Everyone within this radius is affected." +goal_results(integer) : "Bitfield. See TFEntRef" +count(integer) : "Specified score given to the AP's team." +increase_team1(integer) : "Specified score given to team 1" +increase_team2(integer) : "Specified score given to team 2" +increase_team3(integer) : "Specified score given to team 3" +increase_team4(integer) : "Specified score given to team 4" +noise(string) : "WAV file played when this Goal is activated." +lives(integer) : "Added to APA's lives." +health(integer) : "Added to APA's health." +armortype(integer) : "Bitfield. The APAs armortype is set to." +armorvalue(integer) : "APA's armorvalue is set to (0-250)" +armorclass(choices) : "APA's armorclass is set to" : 0 = + [ + 1 : "Shell Resistant" + 2 : "Nail Resistant" + 4 : "Explosion Resistant" + 8 : "Electricity Resistant" + 16 : "Fire Resistant" + ] +frags(integer) : "Added to APA's frags." +ammo_shells(integer) : "Added this number of shells." +ammo_nails(integer) : "Added this number of nails." +ammo_rockets(integer) : "Added this number of rockets." +ammo_cells(integer) : "Added this number of cells." +ammo_detpack(integer) : "Added this number of det packs." +ammo_medikit(integer) : "Added this number of medikits." +no_grenades_1(integer) : "Added to number type 1 TF grenades." +no_grenades_2(integer) : "Added to number type 2 TF grenades." +invincible_finished(integer) : "Number of seconds of invincibility." +invisible_finished(integer) : "Number of seconds of invisibility." +super_damage_finished(integer) : "Number of seconds of quad." +radsuit_finished(integer) : "Number of seconds of radsuit." +items(integer) : "Goal gives this GoalItem to APA." +axhitme(integer) : "Goal removes this GoalItem from APA with it." +delay_time(integer) : "Delay before activation." +wait(integer) : "Goal stays ACTIVE for this long." +activate_goal_no(integer) : "Activate this Goal." +inactivate_goal_no(integer) : "Inactivate this Goal." +remove_goal_no(integer) : "Remove this Goal." +restore_goal_no(integer) : "Restore this Goal." +activate_group_no(integer) : "Activate all Goals in this GoalGroup." +inactivate_group_no(integer) : "Inactivate all Goals in this GoalGroup." +remove_group_no(integer) : "Remove all Goals in this GoalGroup." +restore_group_no(integer) : "Restore all Goals in this GoalGroup." +remove_item_group(integer) : "Removes a GoalGroup from APA" +all_active(integer) : "If whole group ACTIVE, activate last_impulse" +last_impulse(integer) : "Activate goal based on all_active" +remove_spawnpoint(integer) : "Remove spawnpoint with this goal_no." +restore_spawnpoint(integer) : "Restore spawnpoint with this goal_no." +remove_spawngroup(integer) : "Remove all spawnpoints in group_no." +restore_spawngroup(integer) : "Restore all spawnpoints in group_no." +display_item_status1(string) : "Display this when activated" +display_item_status2(string) : "Display this when activated" +display_item_status3(string) : "Display this when activated" +display_item_status4(string) : "Display this when activated" +team_str_home(string) : "Your flag is in it's base" +team_str_moved(string) : "Your flag is lying around" +team_str_carried(string) : "Your flag is being carried by" +non_team_str_home(string) : "The enemy flag is in it's base" +non_team_str_moved(string) : "The enemy flag is lying around" +non_team_str_carried(string) : "The enemy flag is being carried by" +] + +// INFO_TFGOAL_TIMER + +@PointClass base(TfClass) = info_tfgoal_timer : "TF Timer Goal" +[ +goal_effects(integer) : "Bitfield. See TFEntRef" +search_time(integer) : "Time between iterations." +netname(string) : "The name of the Goal." +goal_no(integer) : "Unique ID number of this goal." +group_no(integer) : "ID Number of the goal group this goal belongs to." +goal_state(integer) : "Bitfield. The initial state." +items_allowed(integer) : "AP must have this goal item no" +playerclass(integer) : "Bitfield. Must be of this class(es)." +if_goal_is_active(integer) : "This Goal must be in ACTIVE state." +if_goal_is_inactive(integer) : "This Goal must be in INACTIVE state." +if_goal_is_removed(integer) : "This Goal must be in REMOVED state." +if_group_is_active(integer) : "All Goals in Group must be in ACTIVE." +if_group_is_inactive(integer) : "All Goals in Group must be in INACTIVE." +if_group_is_removed(integer) : "All Goals in Group must be in REMOVED." +if_item_has_moved(integer) : "This Item not moved or carried." +if_item_hasnt_moved(integer) : "This Item must be moved or carried." +has_item_from_group(integer) : "AP must have Item from group no" +maxammo_shells(integer) : "All members of this team are checked for criteria." +maxammo_nails(integer) : "All member not on this team are checked for criteria." +t_length(integer) : "Everyone within this radius is affected." +// When this Goal is successfully activated up, the following variables may be executed +return_item_no(integer) : "Return this GoalItem if not carried" +deathtype(string) : "___ was killed by this goal!\n" +target(string) : "Activate goal with this targetname" +killtarget(string) : "Remove goal with this targetname" +ex_skill_min(integer) : "Skill Minimum" +ex_skill_max(integer) : "Skill Maximum" +goal_results(integer) : "Bitfield. See TFEntRef" +increase_team1(integer) : "Specified score given to team 1" +increase_team2(integer) : "Specified score given to team 2" +increase_team3(integer) : "Specified score given to team 3" +increase_team4(integer) : "Specified score given to team 4" +noise(string) : "WAV file played when this Goal is activated." +lives(integer) : "Added to APA's lives." +health(integer) : "Added to APA's health." +armortype(integer) : "Bitfield. The APAs armortype is set to." +armorvalue(integer) : "APA's armorvalue is set to (0-250)" +armorclass(choices) : "APA's armorclass is set to" : 0 = + [ + 1 : "Shell Resistant" + 2 : "Nail Resistant" + 4 : "Explosion Resistant" + 8 : "Electricity Resistant" + 16 : "Fire Resistant" + ] +frags(integer) : "Added to APA's frags." +ammo_shells(integer) : "Added this number of shells." +ammo_nails(integer) : "Added this number of nails." +ammo_rockets(integer) : "Added this number of rockets." +ammo_cells(integer) : "Added this number of cells." +ammo_detpack(integer) : "Added this number of det packs." +ammo_medikit(integer) : "Added this number of medikits." +no_grenades_1(integer) : "Added to number type 1 TF grenades." +no_grenades_2(integer) : "Added to number type 2 TF grenades." +invincible_finished(integer) : "Number of seconds of invincibility." +invisible_finished(integer) : "Number of seconds of invisibility." +super_damage_finished(integer) : "Number of seconds of quad." +radsuit_finished(integer) : "Number of seconds of radsuit." +items(integer) : "Goal gives this GoalItem to APA." +axhitme(integer) : "Goal removes this GoalItem from APA with it." +delay_time(integer) : "Delay before activation." +wait(integer) : "Goal stays ACTIVE for this long." +activate_group_no(integer) : "Activate all Goals in this GoalGroup." +inactivate_group_no(integer) : "Inactivate all Goals in this GoalGroup." +remove_group_no(integer) : "Remove all Goals in this GoalGroup." +restore_group_no(integer) : "Restore all Goals in this GoalGroup." +activate_goal_no(integer) : "Activate this Goal." +inactivate_goal_no(integer) : "Inactivate this Goal." +remove_goal_no(integer) : "Remove this Goal." +restore_goal_no(integer) : "Restore this Goal." +all_active(integer) : "If whole group ACTIVE, activate last_impulse" +last_impulse(integer) : "Activate goal based on all_active" +remove_spawnpoint(integer) : "Remove spawnpoint with this goal_no." +restore_spawnpoint(integer) : "Restore spawnpoint with this goal_no." +remove_spawngroup(integer) : "Remove all spawnpoints in group_no." +restore_spawngroup(integer) : "Restore all spawnpoints in group_no." +display_item_status1(string) : "Display this when activated" +display_item_status2(string) : "Display this when activated" +display_item_status3(string) : "Display this when activated" +display_item_status4(string) : "Display this when activated" +team_str_home(string) : "Your flag is in it's base" +team_str_moved(string) : "Your flag is lying around" +team_str_carried(string) : "Your flag is being carried by" +non_team_str_home(string) : "The enemy flag is in it's base" +non_team_str_moved(string) : "The enemy flag is lying around" +non_team_str_carried(string) : "The enemy flag is being carried by" +] + +// ITEM_TFGOAL + +@PointClass base(TfClass) = item_tfgoal : "TF Goal Item" +[ +netname(string) : "The name of the Goal." +goal_no(integer) : "Unique ID number of this goal." +group_no(integer) : "ID Number of the goal group this goal belongs to." +owned_by(integer) : "The Team that own this entity." +goal_state(integer) : "Bitfield. The initial state." +mdl(string) : "The mdl used by this Goal if any." +skin(integer) : "The number of the skin on mdl." +goal_activation(integer) : "Bitfield. Activation criteria." +team_no(integer) : "AP must be of this team to activate." +items_allowed(integer) : "AP must have this goal item no" +has_item_from_group(integer) : "AP must have Item from group no" +playerclass(integer) : "Bitfield. Must be of this class(es)." +if_goal_is_active(integer) : "This Goal must be in ACTIVE state." +if_goal_is_inactive(integer) : "This Goal must be in INACTIVE state." +if_goal_is_removed(integer) : "This Goal must be in REMOVED state." +if_group_is_active(integer) : "All Goals in Group must be in ACTIVE." +if_group_is_inactive(integer) : "All Goals in Group must be in INACTIVE." +if_group_is_removed(integer) : "All Goals in Group must be in REMOVED." +if_item_has_moved(integer) : "This Item not moved or carried." +if_item_hasnt_moved(integer) : "This Item must be moved or carried." +else_goal(integer) : "If criteria fails, activate this goal no" +goal_min(string) : "Bounding box min for goal, def is -16 -16 -24" +goal_max(integer) : "Bounding box max for goal, def is 16 16 32" +// When this Goal is successfully activated up, the following variables may be executed +return_item_no(integer) : "Return this GoalItem if not carried" +broadcast(string) : "Message centerprinted to everyone else." +message(string) : "Message centerprinted to AP." +team_broadcast(string) : "Message centerprinted to teammates" +non_team_broadcast(string) : "Message centerprinted to other team" +owners_team_broadcast(string) : "Centerprinted to all owning teammates" +netname_broadcast(string) : "_____ activated this goal.\n" +netname_team_broadcast(string) : "_____ activated your teams goal.\n" +netname_non_team_broadcast(string) : "____ took an enemy flag!\n" +netname_owners_team_broadcast(string) : "____ took your flag!\n" +deathtype(string) : "___ was killed by this goal!\n" +target(string) : "Activate goal with this targetname" +killtarget(string) : "Remove goal with this targetname" +ex_skill_min(integer) : "Skill Minimum" +ex_skill_max(integer) : "Skill Maximum" +goal_effects(integer) : "Bitfield. See TFEntRef" +maxammo_shells(integer) : "All members of this team are affected." +maxammo_nails(integer) : "All members not of this team are affected." +t_length(integer) : "Everyone within this radius is affected." +goal_results(integer) : "Bitfield. See TFEntRef" +count(integer) : "Specified score given to the AP's team." +increase_team1(integer) : "Specified score given to team 1" +increase_team2(integer) : "Specified score given to team 2" +increase_team3(integer) : "Specified score given to team 3" +increase_team4(integer) : "Specified score given to team 4" +noise(string) : "WAV file played when this Goal is activated." +lives(integer) : "Added to APA's lives." +health(integer) : "Added to APA's health." +armortype(integer) : "Bitfield. The APAs armortype is set to." +armorvalue(integer) : "APA's armorvalue is set to (0-250)" +armorclass(choices) : "APA's armorclass is set to" : 0 = + [ + 1 : "Shell Resistant" + 2 : "Nail Resistant" + 4 : "Explosion Resistant" + 8 : "Electricity Resistant" + 16 : "Fire Resistant" + ] +frags(integer) : "Added to APA's frags." +ammo_shells(integer) : "Added this number of shells." +ammo_nails(integer) : "Added this number of nails." +ammo_rockets(integer) : "Added this number of rockets." +ammo_cells(integer) : "Added this number of cells." +ammo_detpack(integer) : "Added this number of det packs." +ammo_medikit(integer) : "Added this number of medikits." +no_grenades_1(integer) : "Added to number type 1 TF grenades." +no_grenades_2(integer) : "Added to number type 2 TF grenades." +invincible_finished(integer) : "Number of seconds of invincibility." +invisible_finished(integer) : "Number of seconds of invisibility." +super_damage_finished(integer) : "Number of seconds of quad." +radsuit_finished(integer) : "Number of seconds of radsuit." +items(integer) : "Goal gives this GoalItem to APA." +axhitme(integer) : "Goal removes this GoalItem from APA with it." +delay_time(integer) : "Delay before activation." +wait(integer) : "Goal stays ACTIVE for this long." +activate_goal_no(integer) : "Activate this Goal." +inactivate_goal_no(integer) : "Inactivate this Goal." +remove_goal_no(integer) : "Remove this Goal." +restore_goal_no(integer) : "Restore this Goal." +activate_group_no(integer) : "Activate all Goals in this GoalGroup." +inactivate_group_no(integer) : "Inactivate all Goals in this GoalGroup." +remove_group_no(integer) : "Remove all Goals in this GoalGroup." +restore_group_no(integer) : "Restore all Goals in this GoalGroup." +remove_item_group(integer) : "Removes a GoalGroup from APA" +all_active(integer) : "If whole group ACTIVE, activate last_impulse" +last_impulse(integer) : "Activate goal based on all_active" +remove_spawnpoint(integer) : "Remove spawnpoint with this goal_no." +restore_spawnpoint(integer) : "Restore spawnpoint with this goal_no." +remove_spawngroup(integer) : "Remove all spawnpoints in group_no." +restore_spawngroup(integer) : "Restore all spawnpoints in group_no." +display_item_status1(string) : "Display this when activated" +display_item_status2(string) : "Display this when activated" +display_item_status3(string) : "Display this when activated" +display_item_status4(string) : "Display this when activated" +team_str_home(string) : "Your flag is in it's base" +team_str_moved(string) : "Your flag is lying around" +team_str_carried(string) : "Your flag is being carried by" +non_team_str_home(string) : "The enemy flag is in it's base" +non_team_str_moved(string) : "The enemy flag is lying around" +non_team_str_carried(string) : "The enemy flag is being carried by" +] + +// INFO_PLAYER_TEAMSPAWN + +@PointClass size(-16 -16 -24, 16 15 24) color(128 0 128) base(Appearflags) = info_player_teamspawn : "TF Player Start" +[ +netname(string) : "netname" +goal_no(integer) : "Goal Number" +group_no(integer) : "Group Number" +team_no(integer) : "Team to Spawn Here" +items(integer) : "Goal given to first to spawn here." +axhitme(integer) : "Removes this GoalItem from APA." +message(string) : "Disp to the first to spawn here." +goal_activation(integer) : "Bitfields. See TFEntRef." +goal_effects(choices) : "Remove spawnpoint after first use." : 0 = + [ + 0 : "Enabled" + 1 : "Disabled" + ] +activate_goal_no(integer) : "Activate this Goal." +items_allowed(integer) : "AP needs this GoalItem." +has_item_from_group(integer) : "AP must have Item from group_no" +playerclass(integer) : "Bitfield. Must be of this class(es)" +if_goal_is_active(integer) : "This Goal must be in ACTIVE state." +if_goal_is_inactive(integer) : "This Goal must be in INACTIVE state." +if_goal_is_removed(integer) : "This Goal must be in REMOVED state." +if_group_is_active(integer) : "All Goals in Group must be in ACTIVE." +if_group_is_inactive(integer) : "All Goals in Group must be in INACTIVE." +if_group_is_removed(integer) : "All Goals in Group must be in REMOVED." +if_item_has_moved(integer) : "This Item not moved or carried." +if_item_hasnt_moved(integer) : "This Item must be moved or carried." +target(string) : "Activate any target with this name" +killtarget(string) : "Remove any target with this name" +goal_state(integer) : "Bitfield. The initial state." +ex_skill_min(integer) : "Skill Minimum" +ex_skill_max(integer) : "Skill Maximum" +count(integer) : "Specified score given to the AP's team." +increase_team1(integer) : "Specified score given to team 1" +increase_team2(integer) : "Specified score given to team 2" +increase_team3(integer) : "Specified score given to team 3" +increase_team4(integer) : "Specified score given to team 4" +noise(string) : "WAV file played when this Goal is activated." +lives(integer) : "Added to APA's lives." +health(integer) : "Added to APA's health." +armortype(integer) : "Bitfield. The APAs armortype is set to." +armorvalue(integer) : "APA's armorvalue is set to (0-250)" +armorclass(choices) : "APA's armorclass is set to" : 0 = + [ + 1 : "Shell Resistant" + 2 : "Nail Resistant" + 4 : "Explosion Resistant" + 8 : "Electricity Resistant" + 16 : "Fire Resistant" + ] +frags(integer) : "Added to APA's frags." +ammo_shells(integer) : "Added this number of shells." +ammo_nails(integer) : "Added this number of nails." +ammo_rockets(integer) : "Added this number of rockets." +ammo_cells(integer) : "Added this number of cells." +ammo_detpack(integer) : "Added this number of det packs." +ammo_medikit(integer) : "Added this number of medikits." +no_grenades_1(integer) : "Added to number type 1 TF grenades." +no_grenades_2(integer) : "Added to number type 2 TF grenades." +invincible_finished(integer) : "Number of seconds of invincibility." +invisible_finished(integer) : "Number of seconds of invisibility." +super_damage_finished(integer) : "Number of seconds of quad." +radsuit_finished(integer) : "Number of seconds of radsuit." +activate_goal_no(integer) : "Activate this Goal." +inactivate_goal_no(integer) : "Inactivate this Goal." +remove_goal_no(integer) : "Remove this Goal." +restore_goal_no(integer) : "Restore this Goal." +activate_group_no(integer) : "Activate all Goals in this GoalGroup." +inactivate_group_no(integer) : "Inactivate all Goals in this GoalGroup." +remove_group_no(integer) : "Remove all Goals in this GoalGroup." +restore_group_no(integer) : "Restore all Goals in this GoalGroup." +remove_item_group(integer) : "Removes a Items APA has from GoalGroup" +all_active(integer) : "If all Group ACTIVE, activate last_impulse goal." +last_impulse(integer) : "If all Group are ACTIVE, activate this Goal." +remove_spawnpoint(integer) : "Remove the spawnpoint with this goal_no." +restore_spawnpoint(integer) : "Restore the spawnpoint with this goal_no." +remove_spawngroup(integer) : "Remove all spawnpoints with this group_no." +restore_spawngroup(integer) : "Restore all spawnpoints with this group_no." +] + diff --git a/tools/trenchbroom/games/Quake2/GameConfig.cfg b/tools/trenchbroom/games/Quake2/GameConfig.cfg new file mode 100644 index 0000000..a030b46 --- /dev/null +++ b/tools/trenchbroom/games/Quake2/GameConfig.cfg @@ -0,0 +1,245 @@ +{ + "version": 9, + "name": "Quake 2", + "icon": "Icon.png", + "fileformats": [ + { "format": "Quake2" }, + { "format": "Quake2 (Valve)"} + ], + "filesystem": { + "searchpath": "baseq2", + "packageformat": { "extension": ".pak", "format": "idpak" } + }, + "materials": { + "root": "textures", + "extensions": [".wal"], + "palette": "pics/colormap.pcx" + }, + "entities": { + "definitions": [ "Quake2.fgd" ], + "defaultcolor": "0.6 0.6 0.6 1.0" + }, + "tags": { + "brush": [ + { + "name": "Areaportal", + "attribs": [ "transparent" ], + "match": "classname", + "pattern": "*_areaportal", + "material": "e1u1/trigger" + }, + { + "name": "Trigger", + "attribs": [ "transparent" ], + "match": "classname", + "pattern": "trigger*", + "material": "e1u1/trigger" + } + ], + "brushface": [ + { + "name": "Clip", + "attribs": [ "transparent" ], + "match": "contentflag", + "flags": [ "clip"] + }, + { + "name": "Detail", + "match": "contentflag", + "flags": [ "detail" ] + }, + { + "name": "Hint", + "attribs": [ "transparent" ], + "match": "surfaceflag", + "flags": ["hint"] + }, + { + "name": "Liquid", + "match": "contentflag", + "flags": [ "lava", "slime", "water" ] + }, + { + "name": "Nodraw", + "attribs": [ "transparent" ], + "match": "surfaceflag", + "flags": [ "nodraw" ] + }, + { + "name": "Origin", + "attribs": [ "transparent" ], + "match": "contentflag", + "flags": [ "origin" ] + }, + { + "name": "Skip", + "attribs": [ "transparent" ], + "match": "surfaceflag", + "flags": ["skip"] + }, + { + "name": "Sky", + "attribs": [], + "match": "surfaceflag", + "flags": ["sky"] + }, + { + "name": "Slick", + "attribs": [], + "match": "surfaceflag", + "flags": ["slick"] + }, + { + "name": "Transparent", + "attribs": [ "transparent" ], + "match": "surfaceflag", + "flags": [ "trans33", "trans66" ] + } + ] + }, + "faceattribs": { + "surfaceflags": [ + { + "name": "light", + "description": "Emit light from the surface, brightness is specified in the 'value' field" + }, + { + "name": "slick", + "description": "The surface is slippery" + }, + { + "name": "sky", + "description": "The surface is sky, the texture will not be drawn, but the background sky box is used instead" + }, + { + "name": "warp", + "description": "The surface warps (like water textures do)" + }, + { + "name": "trans33", + "description": "The surface is 33% transparent" + }, + { + "name": "trans66", + "description": "The surface is 66% transparent" + }, + { + "name": "flowing", + "description": "The texture wraps in a downward 'flowing' pattern (warp must also be set)" + }, + { + "name": "nodraw", + "description": "Used for non-fixed-size brush triggers and clip brushes" + }, + { + "name": "hint", + "description": "Make a primary bsp splitter" + }, + { + "name": "skip", + "description": "Completely ignore, allowing non-closed brushes" + } + ], + "contentflags": [ + { + "name": "solid", + "description": "Default for all brushes" + }, // 1 << 0 + { + "name": "window", + "description": "Brush is a window (not really used)" + }, // 1 << 1 + { + "name": "aux", + "description": "Unused by the engine" + }, // 1 << 2 + { + "name": "lava", + "description": "The brush is lava" + }, // 1 << 3 + { + "name": "slime", + "description": "The brush is slime" + }, // 1 << 4 + { + "name": "water", + "description": "The brush is water" + }, // 1 << 5 + { + "name": "mist", + "description": "The brush is non-solid" + }, // 1 << 6 + { "unused": true }, // 1 << 7 + { "unused": true }, // 1 << 8 + { "unused": true }, // 1 << 9 + { "unused": true }, // 1 << 10 + { "unused": true }, // 1 << 11 + { "unused": true }, // 1 << 12 + { "unused": true }, // 1 << 13 + { "unused": true }, // 1 << 14 + { "unused": true }, // 1 << 15 + { + "name": "playerclip", + "description": "Player cannot pass through the brush (other things can)" + }, // 1 << 16 + { + "name": "monsterclip", + "description": "Monster cannot pass through the brush (player and other things can)" + }, // 1 << 17 + { + "name": "current_0", + "description": "Brush has a current in direction of 0 degrees" + }, // 1 << 18 + { + "name": "current_90", + "description": "Brush has a current in direction of 90 degrees" + }, // 1 << 19 + { + "name": "current_180", + "description": "Brush has a current in direction of 180 degrees" + }, // 1 << 20 + { + "name": "current_270", + "description": "Brush has a current in direction of 270 degrees" + }, // 1 << 21 + { + "name": "current_up", + "description": "Brush has a current in the up direction" + }, // 1 << 22 + { + "name": "current_dn", + "description": "Brush has a current in the down direction" + }, // 1 << 23 + { + "name": "origin", + "description": "Special brush used for specifying origin of rotation for rotating brushes" + }, // 1 << 24 + { + "name": "monster", + "description": "Purpose unknown" + }, // 1 << 25 + { + "name": "corpse", + "description": "Purpose unknown" + }, // 1 << 26 + { + "name": "detail", + "description": "Detail brush" + }, // 1 << 27 + { + "name": "translucent", + "description": "Use for opaque water that does not block vis" + }, // 1 << 28 + { + "name": "ladder", + "description": "Brushes with this flag allow a player to move up and down a vertical surface" + } // 1 << 29 + ] + }, + "softMapBounds":"-16384 -16384 -16384 16384 16384 16384", + "compilationTools": [ + { "name": "bsp", "description": "Path to your directory containing your bsp compiler. ${bsp}." }, + { "name": "vis", "description": "Path to your directory containing your vis compiler. ${vis}" }, + { "name": "light", "description": "Path to your directory containing your light compiler. ${light}" } + ] +} diff --git a/tools/trenchbroom/games/Quake2/Icon.png b/tools/trenchbroom/games/Quake2/Icon.png new file mode 100644 index 0000000..85f062d Binary files /dev/null and b/tools/trenchbroom/games/Quake2/Icon.png differ diff --git a/tools/trenchbroom/games/Quake2/Quake2.fgd b/tools/trenchbroom/games/Quake2/Quake2.fgd new file mode 100644 index 0000000..73e5cbd --- /dev/null +++ b/tools/trenchbroom/games/Quake2/Quake2.fgd @@ -0,0 +1,960 @@ +// +// Quake 2 game definition file (.fgd) +// +// Originally written by by autolycus +// Special thanks to: Disruptor, Zoid, Zaphod, Imaginos, and EutecTic. +// +// Lasted updated by xaGe : 20200415 + +// +// worldspawn +// + +// 0302 - added "nextmap" key +@SolidClass = worldspawn : "World entity" +[ + sky(string) : "Environment map name" + skyaxis(string) : "Vector axis for rotating sky" + skyrotate(string) : "Speed of rotation (degrees/second)" + sounds(integer) : "CD Track Number" : 1 + gravity(integer) : "Gravity" : 800 + message(string) : "Level name" + nextmap(string) : "Next map (DM only)" +] + +// +// base marker definitions +//model({ "path": ":models/items/keys/target/tris.md2" }) = + +@baseclass = Appearflags [ + spawnflags(Flags) = + [ + 256 : "Not in Easy" : 0 + 512 : "Not in Normal" : 0 + 1024 : "Not in Hard" : 0 + 2048 : "Not in Deathmatch" : 0 + ] +] +@baseclass = Angle [ angle(integer) : "Direction" ] +@baseclass = Targetname [ targetname(target_source) : "Name" ] +@baseclass = Target [ target(target_destination) : "Target" ] + +// +// player start, deathmatch, coop, deathmatch intermission +// + +@baseclass base(Appearflags, Targetname) size(-16 -16 -24, 16 16 32) color(0 255 0) model({ "path": ":models/monsters/insane/tris.md2", "frame":209, "skin":1}) = PlayerClass [] +@PointClass base(PlayerClass) = info_player_start : "Player 1 start" [] +@PointClass base(PlayerClass) = info_player_deathmatch : "Player deathmatch start" [] +@PointClass base(PlayerClass) = info_player_coop : "Player cooperative start" [] +@PointClass base(PlayerClass) = info_player_intermission : "Deathmatch intermission point" +[ + angles(string) : "pitch yaw roll" +] + +// Notes on the 'team' key: First of all, it's really only useful in DM because it creates a +// random respawn pattern. Let's say that in one spot, you want to have the shotgun, Quad +// damage and mega health item to respawn in alternance. Place all of them in approximately +// the same location, team them and voila! The FIRST item that you place in the map will be +// the team MASTER - the others will be SLAVES. In DM play, the Master will be the first one +// to spawn. Once the Master is picked up, the respawn pattern becomes RANDOM: it could be +// the same or one of the other 2. If you try to use this in a Single Player map, it's +// pretty useless because only the team MASTER spawns and the others never appear obviously. + +@BaseClass base(Appearflags, Target) color(76 76 255) size(-16 -16 -16, 16 16 16) = Ammo +[ + team(string) : "Team" +] + +@PointClass base(Ammo) model({ "path": ":models/items/ammo/shells/medium/tris.md2" }) = ammo_shells : "Shotgun ammo" [] +@PointClass base(Ammo) model({ "path": ":models/items/ammo/bullets/medium/tris.md2" }) = ammo_bullets : "Machine/Chain gun ammo" [] +@PointClass base(Ammo) model({ "path": ":models/items/ammo/cells/medium/tris.md2" }) = ammo_cells : "Blaster/BFG ammo" [] +@PointClass base(Ammo) model({ "path": ":models/items/ammo/grenades/medium/tris.md2" }) = ammo_grenades : "Grenades" [] +@PointClass base(Ammo) model({ "path": ":models/items/ammo/rockets/medium/tris.md2" }) = ammo_rockets : "Rockets" [] +@PointClass base(Ammo) model({ "path": ":models/items/ammo/slugs/medium/tris.md2" }) = ammo_slugs : "Rail gun ammo" [] + +// Keep in mind when using func_areaportal that it must +// *completely* separate two areas. otherwise, you will +// get an error message and the areaportal will not work +// +// 0221 - is there any point in a "style" key? +@SolidClass base(Appearflags, Targetname) = func_areaportal : "Area portal (Vis blocker)" [] + +// 0221 - added "pathtarget" +// 0221 - changed "sounds" information +@SolidClass base(Appearflags, Target, Targetname) color(0 128 204) = func_button : "Button" +[ + pathtarget(string) : "Elevator level target" + speed(integer) : "Speed" : 40 + wait(choices) : "Wait before reset" : 1 = + [ + -1 : "Never Return" + ] + lip(integer) : "Lip remaining after move" : 4 + health(integer) : "Health (shootable)" + sounds(choices) : "Sounds" : 0 = + [ + 0 : "Audible" + 1 : "Silent" + ] +// sounds(choices) : "Sounds" : 2 = +// [ +// 1 : "Silent" +// 2 : "Steam Metal" +// 3 : "Wodden Clunk" +// 4 : "Metallic Click" +// 5 : "In-Out" +// ] + message(string) : "Activation message" + _minlight(integer) : "Minimum light (optional)" +] + +// 0221 - added "count" key...oops :) +@PointClass base(Appearflags, Targetname) color(0 0 255) size(-8 -8 -8, 8 8 8) = func_clock : "Clock" +[ + spawnflags(Flags) = + [ + 1 : "Timer Up" : 0 + 2 : "Timer Down" : 0 + 4 : "Start Off" : 0 + 8 : "Multi Use" : 0 + ] + count(integer) : "Clock Count" + pathtarget(string) : "Target" + style(choices) : "Style" : 0 = + [ + 0 : "xx" + 1 : "xx:xx" + 2 : "xx:xx:xx" + ] +] + +// func_conveyor code is incomplete. use the surface attribute "flowing" +// and the "current" content flag. (texture won't scroll) +// +// 0221 - added _minlight +@SolidClass base(Appearflags, Targetname) color(0 128 204) = func_conveyor : "Conveyor belt" +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + 2 : "Toggle" : 0 + ] + speed(integer) : "Speed" : 100 + _minlight(integer) : "Minimum light (optional)" +] + +// 0221 - updated "sounds" information +// 0221 - added "killtarget" +@SolidClass base(Angle, Appearflags, Targetname, Target) color(0 128 204) = func_door : "Door" +[ + spawnflags(Flags) = + [ + 1 : "Start Open" : 0 + 4 : "Crusher" : 0 + 8 : "No Monsters" : 0 + 16 : "Animated" : 0 + 32 : "Toggle" : 0 + 64 : "Animated Fast" : 0 + ] + killtarget(string) : "Kill Target" + team(string) : "Team" + message(string) : "Trigger message" + health(integer) : "Health (shootable)" + speed(integer) : "Speed" : 100 + wait(choices) : "Wait before close" : 3 = + [ + -1 : "Stay open" + ] + lip(integer) : "Lip remaining after move" : 8 + dmg(integer) : "Damage when blocked" : 2 + sounds(choices) : "Sounds" : 0 = + [ + 0 : "Audible" + 1 : "Silent" + ] +// sounds(choices) : "Sounds" : 3 = +// [ +// 1 : "Silent" +// 2 : "Light" +// 3 : "Medium" +// 4 : "Heavy" +// ] + _minlight(integer) : "Minimum light (optional)" +] + +// 0221 - added "killtarget" and "target" keys +// 0221 - updated "sounds" info +// 0221 - removed "lip" key +@SolidClass base(Appearflags, Targetname, Target) color(0 128 204) = func_door_rotating : "Rotating Door" +[ + spawnflags(Flags) = + [ + 1 : "Start Open" : 0 + 2 : "Reverse" : 0 + 4 : "Crusher" : 0 + 8 : "No Monsters" : 0 + 16 : "Animated" : 0 + 32 : "Toggle" : 0 + 64 : "X Axis" : 0 + 128 : "Y Axis" : 0 + ] + killtarget(string) : "Kill Target" + team(string) : "Team" + distance(integer) : "Degrees of rotation" : 90 + message(string) : "Trigger message" + health(integer) : "Health (shootable)" + speed(integer) : "Speed" : 100 + wait(choices) : "Wait before close" : 3 = + [ + -1 : "Stay open" + ] + dmg(integer) : "Damage when blocked" : 2 + sounds(choices) : "Sounds" : 0 = + [ + 0 : "Audible" + 1 : "Silent" + ] +// sounds(choices) : "Sounds" : 3 = +// [ +// 1 : "Silent" +// 2 : "Light" +// 3 : "Medium" +// 4 : "Heavy" +// ] + _minlight(integer) : "Minimum light (optional)" +] + +// 0221 - added "_minlight" key (even tho you dont want it to stand out) +// 0221 - added "message" key +// 0221 - removed "team" key +@SolidClass base(Angle, Appearflags, Targetname) color(0 128 204) = func_door_secret : "Secret Door" +[ + spawnflags(Flags) = + [ + 1 : "Always shoot" : 0 + 2 : "1st Left" : 0 + 4 : "1st Down" : 0 + ] + dmg(integer) : "Damage when blocked" : 2 + wait(choices) : "Wait before close" : 5 = + [ + -1 : "Stay open" + ] + message(string) : "Message" + _minlight(integer) : "Minimum light (optional)" +] + +// not visible in DM mode +// +// 0221 - added "_minlight" key (even tho you dont want it to stand out) +@SolidClass base(Appearflags, Targetname, Target) color(0 128 204) = func_explosive : "Exploding/Breakable brush" +[ + spawnflags(Flags) = + [ + 1 : "Trigger Spawn" : 0 + 2 : "Animated" : 0 + 4 : "Animated Fast" : 0 + ] + health(integer) : "Health" : 100 + mass(integer) : "Mass (debris)" : 75 + dmg(integer) : "Damage" : 0 + _minlight(integer) : "Minimum light (optional)" +] + +@SolidClass base(Appearflags, Targetname) color(255 0 0) = func_killbox : "Instant death" [] + +// 0221 - added "_minlight" key +@SolidClass base(Appearflags, Targetname) color (0 128 204) = func_object : "Solid bmodel, will fall if its support is removed" +[ + spawnflags(Flags) = + [ + 1 : "Trigger Spawn" : 0 + 2 : "Animated" : 0 + 4 : "Animated Fast" : 0 + ] + _minlight(integer) : "Minimum light (optional)" +] + +// 0221 - removed "sounds" key +@SolidClass base(Appearflags, Targetname) color(0 128 204) = func_plat : "Platform" +[ + spawnflags(Flags) = + [ + 1 : "Plat Low Trigger" : 0 + ] + speed(integer) : "Speed" : 100 + accel(integer) : "Acceleration" : 500 + lip(integer) : "Lip remaining after move" : 8 + height(integer) : "Movement distance" + _minlight(integer) : "Minimum light (optional)" +] + +// 0222 - added "team" key +@SolidClass base(Appearflags, Targetname) color(0 128 204) = func_rotating : "Rotating brush" +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + 2 : "Reverse" : 0 + 4 : "X Axis" : 0 + 8 : "Y Axis" : 0 + 16 : "Pain on Touch" : 0 + 32 : "Block Stops" : 0 + 64 : "Animated" : 0 + 128 : "Animated Fast" : 0 + ] + team(string) : "Team" + speed(integer) : "Speed" : 100 + dmg(integer) : "Damage when blocked" : 2 + _minlight(integer) : "Minimum light (optional)" +] + +@PointClass base(Appearflags, Targetname, Target) color(76 25 153) size(-8 -8 -8, 8 8 8) = func_timer : "Timer" +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + ] + wait(integer) : "Base wait time" : 1 + random(integer) : "Wait variance (+/-)" + delay(integer) : "Delay before first firing" + pausetime(integer) : "Additional delay" +] + +// 0219 - added "team" key +@SolidClass base(Appearflags, Targetname) color(0 128 204) = func_train : "Moving platform" +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + 2 : "Toggle" : 0 + 4 : "Block Stops" : 0 + ] + target(string) : "First stop target" + team(string) : "Team" + speed(integer) : "Speed" : 100 + dmg(integer) : "Damage when blocked" : 2 + noise(string) : "Sound (path/file.wav)" + _minlight(integer) : "Minimum light (optional)" +] + +// 0221 - added a "_minlight" key +@SolidClass base(Appearflags, Targetname) color(0 128 204) = func_wall : "Solid Wall" +[ + spawnflags(Flags) = + [ + 1 : "Trigger Spawn" : 0 + 2 : "Toggle" : 0 + 4 : "Start On" : 0 + 8 : "Animated" : 0 + 16 : "Animated Fast" : 0 + ] + _minlight(integer) : "Minimum light (optional)" +] + +// must never be transparent? +// +// 0221 - added a "_minlight" key +@SolidClass base(Appearflags, Targetname) color(0 128 204) = func_water : "Moveable water" +[ + spawnflags(Flags) = + [ + 1 : "Start Open" : 0 + ] + speed(integer) : "Speed" : 25 + wait(choices) : "Wait before return" : -1 = + [ + -1 : "Toggle" + ] + lip(integer) : "Lip remaining after move" + sounds(Choices) : "Sounds" : 1 = + [ + 0 : "No Sounds" + 1 : "Water" + 2 : "Lava" + ] + team(string) : "Team" + _minlight(integer) : "Minimum light (optional)" +] + +@PointClass base(Appearflags, Targetname) color(0 128 0) size(-4 -4 -4, 4 4 4) = info_null : "Spotlight target" [] +@PointClass base(info_null) = info_notnull : "Lightning target" [] + +@BaseClass base(Appearflags, Target) color(76 76 255) size(-16 -16 -16, 16 16 16) = Items +[ + team(string) : "Team" +] + +@PointClass base(Items) model({ "path": ":models/items/adrenal/tris.md2" }) = item_adrenaline : "+1 to max health" [] +@PointClass base(Items) model({ "path": ":models/items/c_head/tris.md2" }) = item_ancient_head : "+2 to max health" [] +@PointClass base(Items) model({ "path": ":models/items/armor/body/tris.md2" }) = item_armor_body : "Body armor" [] +@PointClass base(Items) model({ "path": ":models/items/armor/combat/tris.md2" }) = item_armor_combat : "Combat armor" [] +@PointClass base(Items) model({ "path": ":models/items/armor/jacket/tris.md2" }) = item_armor_jacket : "Jacket armor" [] +@PointClass base(Items) model({ "path": ":models/items/armor/shard/tris.md2" }) = item_armor_shard : "Armor shard" [] +@PointClass base(Items) model({ "path": ":models/items/band/tris.md2" }) = item_bandolier : "Equipment belt" [] +@PointClass base(Items) model({ "path": ":models/items/breather/tris.md2" }) = item_breather : "Underwater breather" [] +@PointClass base(Items) model({ "path": ":models/items/enviro/tris.md2" }) = item_enviro : "Enviro-Suit" [] +@PointClass base(Items) model({ "path": ":models/items/healing/medium/tris.md2" }) = item_health : "+10 health" [] +@PointClass base(Items) model({ "path": ":models/items/healing/stimpack/tris.md2" }) = item_health_small : "+2 health" [] +@PointClass base(Items) model({ "path": ":models/items/healing/large/tris.md2" }) = item_health_large : "+25 health" [] +@PointClass base(Items) model({ "path": ":models/items/mega_h/tris.md2" }) = item_health_mega : "+100 health" [] +@PointClass base(Items) model({ "path": ":models/items/invulner/tris.md2" }) = item_invulnerability : "Invulnerability" [] +@PointClass base(Items) model({ "path": ":models/items/pack/tris.md2" }) = item_pack : "Heavy backpack" [] +@PointClass base(Items) model({ "path": ":models/items/armor/screen/tris.md2" }) = item_power_screen : "Power screen" [] +@PointClass base(Items) model({ "path": ":models/items/armor/shield/tris.md2" }) = item_power_shield : "Power shield" [] +@PointClass base(Items) model({ "path": ":models/items/quaddama/tris.md2" }) = item_quad : "Quad damage" [] +@PointClass base(Items) model({ "path": ":models/items/silencer/tris.md2" }) = item_silencer : "Silencer" [] + +@BaseClass base(Appearflags, Target) color(0 128 204) size(-16 -16 -16, 16 16 16) = Keys [] + +@PointClass base(Keys) model({ "path": ":models/items/keys/target/tris.md2" }) = key_airstrike_target : "Tank commander's head" [] +@PointClass base(Keys) model({ "path": ":models/items/keys/key/tris.md2" }) = key_blue_key : "Normal door key - blue" [] +@PointClass base(Keys) model({ "path": ":models/monsters/commandr/head/tris.md2" }) = key_commander_head : "Tank commander's head" [] +@PointClass base(Keys) model({ "path": ":models/items/keys/data_cd/tris.md2" }) = key_data_cd : "Key for computer centers" [] +@PointClass base(Keys) model({ "path": ":models/items/keys/spinner/tris.md2" }) = key_data_spinner : "Key for city computer" [] +@PointClass base(Keys) model({ "path": ":models/items/keys/pass/tris.md2" }) = key_pass : "Security pass for secret level" [] + +// 0301 - added "targetname" key +@PointClass base(Keys, Targetname) model({ "path": ":models/items/keys/power/tris.md2" }) = key_power_cube : "Warehouse circuits" +[ + spawnflags(Flags) = + [ + 1 : "Trigger Spawn" : 0 + 2 : "No Touch" : 0 + ] +] +@PointClass base(Keys) model({ "path": ":models/items/keys/pyramid/tris.md2" }) = key_pyramid : "Key for entrance to jail3" [] +@PointClass base(Keys) model({ "path": ":models/items/keys/red_key/tris.md2" }) = key_red_key : "normal door key - red" [] + +@PointClass base(Appearflags, Target, Targetname) color(0 255 0) size(-8 -8 -8, 8 8 8) = light : "Light" +[ + spawnflags(Flags) = + [ + 1 : "Start Off" : 0 + ] + light(integer) : "Brightness" : 300 + style(Choices) : "Style" : 0 = + [ + 0 : "Normal" + 1 : "Flicker #1" + 6 : "Flicker #2" + 2 : "Slow Strong Pulse" + 3 : "Candle #1" + 7 : "Candle #2" + 8 : "Candle #3" + 4 : "Fast Strobe" + 5 : "Gentle Pulse #1" + 9 : "Slow Strobe" + 10 : "Fluorescent Flicker" + 11 : "Slow pulse, no black" + ] + _cone(integer) : "Size of light (spotlight)" : 10 +] + +@PointClass base(light) color(0 255 0) size(-2 -2 -12, 2 2 12) model({ "path": ":models/objects/minelite/light1/tris.md2", "skin": 0 }) = light_mine1 : "Clean fluorescent light fixture" [spawnflags(Flags) = [ 1 : "" : 0 ]] +@PointClass base(light) color(0 255 0) size(-2 -2 -12, 2 2 12) model({ "path": ":models/objects/minelite/light2/tris.md2", "skin": 0 }) = light_mine2 : "Dusty fluorescent light fixture" [spawnflags(Flags) = [ 1 : "" : 0]] + + + + +// actor code is still broken...leaving this in because i know *someone* will fix +// this because its pretty damn cool. +@PointClass base(PlayerClass, Target) = misc_actor : "Actor" +[ + health(integer) : "Health" : 100 +] +@PointClass base(Appearflags, Targetname) = target_actor : "Actor path" +[ + spawnflags(Flags) = + [ + 1 : "Jump" : 0 + 2 : "Shoot" : 0 + 4 : "Attack" : 0 + 16 : "Hold" : 0 + 32 : "Brutal" : 0 + ] + target(string) : "Next path target" + pathtarget(string) : "Action target" + wait(integer) : "Pause time" + message(string) : "Message" + speed(integer) : "Forward (jump)" : 200 + height(integer) : "Height (jump)" : 200 +] + +// 0224 - changed banner size from (-4 -4 -4, 4 4 4) to (-4 -4 0, 4 4 246) +@PointClass base(Appearflags) color(255 128 0) size(-4 -4 0, 4 4 246) model({ "path": ":models/objects/banner/tris.md2" }) = misc_banner : "Flowing banner" [] + +@PointClass base(Appearflags) color(255 128 0) size(-8 -8 -8, 8 8 8) model({ "path": ":models/objects/black/tris.md2" }) = misc_blackhole : "Blackhole" [] + +@PointClass base(Appearflags) color(255 128 0) size(-16 -16 0, 16 16 16) model({{ + spawnflags & 32 -> { "path": ":models/deadbods/dude/tris.md2", "frame": 5 }, + spawnflags & 16 -> { "path": ":models/deadbods/dude/tris.md2", "frame": 4 }, + spawnflags & 8 -> { "path": ":models/deadbods/dude/tris.md2", "frame": 3 }, + spawnflags & 4 -> { "path": ":models/deadbods/dude/tris.md2", "frame": 2 }, + spawnflags & 2 -> { "path": ":models/deadbods/dude/tris.md2", "frame": 1 }, + ":models/deadbods/dude/tris.md2" + }}) = misc_deadsoldier : "Dead guys! 6 of em!" +[ + spawnflags(Flags) = + [ + 1 : "On Back" : 0 + 2 : "On Stomach" : 0 + 4 : "Back, Decap" : 0 + 8 : "Fetal Position" : 0 + 16 : "Sitting, Decap" : 0 + 32 : "Impaled" : 0 + ] +] + +// The following three entities are eye-candy - they don't do anything +@PointClass base(Appearflags) color(255 128 0) size(-32 -32 -16, 32 32 32) model({ "path": ":models/monsters/tank/tris.md2", "frame":254, "skin": 0}) = misc_eastertank : "Tank sitting down. Make him a chair out of brushes." [] +@PointClass base(Appearflags) color(255 128 0) size(-32 -32 0, 32 32 32) model({ "path": ":models/monsters/bitch/tris.md2", "frame":208}) = misc_easterchick : "Chick #1 sitting: Place her near misc_eastertank." [] +@PointClass base(Appearflags) color(255 128 0) size(-32 -32 0, 32 32 32) model({ "path": ":models/monsters/bitch/tris.md2", "frame":248}) = misc_easterchick2 : "Chick #2 sitting w/ different pose. Can be placed close to misc_eastertank's for full effect." [] + +// 0225 - removed "target" key - id concluded being able to target +// something with a movable barrel was a bug and removed that function :( +@PointClass base(Appearflags, Targetname) color(0 128 204) size(-16 -16 0, 16 16 40) model({ "path": ":models/objects/barrels/tris.md2" }) = misc_explobox : "Large exploding box" +[ + mass(integer) : "Mass" : 100 + health(integer) : "Health" : 80 + dmg(integer) : "Damage" : 150 +] + +// set angle for gib direction, otherwise it just drops +@PointClass base(Appearflags) color(255 0 0) size(-8 -8 -8, 8 8 8) model({ "path": ":models/objects/gibs/arm/tris.md2" }) = misc_gib_arm : "arm gib, use with target_spawner" [] +@PointClass base(Appearflags) color(255 0 0) size(-8 -8 -8, 8 8 8) model({ "path": ":models/objects/gibs/head/tris.md2" }) = misc_gib_head : "head gib, use with target_spawner" [] +@PointClass base(Appearflags) color(255 0 0) size(-8 -8 -8, 8 8 8) model({ "path": ":models/objects/gibs/arm/tris.md2" }) = misc_gib_leg : "leg gib, use with target_spawner" [] + + + +// new +@PointClass base(Appearflags, Targetname, Target) color(255 128 0) size(-16 -16 -24, 16 16 32) model({{ + spawnflags & 32 -> { "path": ":models/monsters/insane/tris.md2", "frame": 0 }, + spawnflags & 16 -> { "path": ":models/monsters/insane/tris.md2", "frame": 74 }, + spawnflags & 8 -> { "path": ":models/monsters/insane/tris.md2", "frame": 252 }, + spawnflags & 4 -> { "path": ":models/monsters/insane/tris.md2", "frame": 38 }, + spawnflags & 2 -> { "path": ":models/monsters/insane/tris.md2", "frame": 0 }, + ":models/monsters/insane/tris.md2" + }}) = misc_insane : "Insane Soldiers" +[ + spawnflags(Flags) = + [ + 1 : "Ambush" : 0 + 2 : "Trigger Spawn" : 0 + 4 : "Crawl" : 0 + 8 : "Crucified" : 0 + 16 : "Stand Ground" : 0 + 32 : "Always Stand" : 0 + ] + deathtarget(string) : "Entity to trigger at death" + killtarget(string) : "Entity to remove at death" + item(string) : "Item to spawn at death" +] + +@PointClass base(Appearflags, Targetname) color(255 128 0) size(-64 -64 0, 64 64 128) model({ "path": ":models/objects/satellite/tris.md2" }) = misc_satellite_dish : "Satellite Dish" [] +@PointClass base(Appearflags, Targetname) color(255 128 0) size(-16 -16 0, 16 16 32) model({ "path": ":models/ships/strogg1/tris.md2" }) = misc_strogg_ship : "Strogg ship for flybys" +[ + target(string) : "First path target" + speed(integer) : "Speed" + +] + +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-32 -32 -24, 32 32 -16) model({ "path": ":models/objects/dmspot/tris.md2", "skin": 1 }) = misc_teleporter : "Teleporter: To hide the teleport pads, place them units 10 units into a brush." [ target(string) : "Teleport Destination" ] +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-32 -32 -24, 32 32 -16) model({ "path": ":models/objects/dmspot/tris.md2", "skin": 0 }) = misc_teleporter_dest : "Teleport Destination: To hide the teleport pads, place them units 10 units into a brush." [] +@PointClass base(Appearflags) color(255 128 0) size(-176 -120 -24, 176 120 72) model({ "path": ":models/ships/bigviper/tris.md2" }) = misc_bigviper : "Large stationary Viper" [] +@PointClass base(Appearflags, Targetname) color(255 128 0) size(-16 -16 0, 16 16 32) model({ "path": ":models/ships/viper/tris.md2" }) = misc_viper : "Viper for flybys" +[ + target(string) : "First path target" + speed(integer) : "Speed" + +] +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) model({ "path": ":models/objects/bomb/tris.md2" }) = misc_viper_bomb : "Viper Bomb" +[ + dmg(integer) : "Damage" +] + +// +// Monsters! +// + +@BaseClass base(Appearflags, Target, Targetname) color(255 128 0) size(-16 -16 -24, 16 16 32) = Monsters +[ + spawnflags(Flags) = + [ + 1 : "Ambush" : 0 + 2 : "Trigger Spawn" : 0 + 4 : "Sight" : 0 + ] + combattarget(string) : "Point combat target" + deathtarget(string) : "Entity to trigger at death" + killtarget(string) : "Entity to remove at death" + item(string) : "Spawn Item" +] + +@PointClass base(Monsters) model({ "path": ":models/monsters/berserk/tris.md2" }) = monster_berserk : "Berserker" [] +@PointClass base(Monsters) size(-56 -56 0, 56 56 80) model({ "path": ":models/monsters/boss2/tris.md2" }) = monster_boss2 : "Hornet" [] + +// Just fidgets in one spot and teleports away when triggered +// +// 0221 - removed Monsters class inheritance +@PointClass base(Appearflags, Targetname) size(-32 -32 0, 32 32 80) model({ "path": ":models/monsters/boss3/rider/tris.md2", "frame": 414}) = monster_boss3_stand : "Stationnary Makron" [] +@PointClass base(Monsters) model({ "path": ":models/monsters/brain/tris.md2" }) = monster_brain : "Brains" [] +@PointClass base(Monsters) model({ "path": ":models/monsters/bitch/tris.md2" }) = monster_chick : "Iron Maiden" [] +@PointClass base(Appearflags, Targetname) color(255 128 0) size(-32 -32 0, 32 32 48) model({ "path": ":models/monsters/commandr/tris.md2" }) = monster_commander_body : "Tank commander's decapitated body" [] +@PointClass base(Monsters) model({ "path": ":models/monsters/flipper/tris.md2" }) = monster_flipper : "Barracuda shark" [] +@PointClass base(Monsters) model({ "path": ":models/monsters/float/tris.md2" }) = monster_floater : "Technician" [] +@PointClass base(Monsters) model({ "path": ":models/monsters/flyer/tris.md2" }) = monster_flyer : "Flyer" [] +@PointClass base(Monsters) size(-32 -32 -24, 32 32 64) model({ "path": ":models/monsters/gladiatr/tris.md2" }) = monster_gladiator : "Gladiator" [] +@PointClass base(Monsters) model({ "path": ":models/monsters/gunner/tris.md2" }) = monster_gunner : "Gunner" [] +@PointClass base(Monsters) model({ "path": ":models/monsters/hover/tris.md2" }) = monster_hover : "Icarus" [] +@PointClass base(Monsters) model({ "path": ":models/monsters/infantry/tris.md2", "frame": 64}) = monster_infantry : "Infantry" [] +@PointClass base(Monsters) size(-80 -80 0, 90 90 140) model({ "path": ":models/monsters/boss3/jorg/tris.md2" }) = monster_jorg : "Jorg" [] + +// 0221 - this entity can only spawn once the Jorg dies ... im sure someone will change that tho +@PointClass base(Monsters) size(-32 -32 0, 32 32 80) model({ "path": ":models/monsters/boss3/rider/tris.md2", "frame": 414}) = monster_makron : "Makron" [] +@PointClass base(Monsters) model({ "path": ":models/monsters/medic/tris.md2" }) = monster_medic : "Medic" [] +@PointClass base(Monsters) size(-32 -32 -24, 32 32 32) model({ "path": ":models/monsters/mutant/tris.md2" }) = monster_mutant : "Mutant" [] +@PointClass base(Monsters) model({ "path": ":models/monsters/parasite/tris.md2" }) = monster_parasite : "Parasite" [] +@PointClass base(Monsters) model({ "path": ":models/monsters/soldier/tris.md2", "skin": 0 }) = monster_soldier_light : "Light Soldier" [] +@PointClass base(Monsters) model({ "path": ":models/monsters/soldier/tris.md2", "skin": 2 }) = monster_soldier : "Soldier" [] +@PointClass base(Monsters) model({ "path": ":models/monsters/soldier/tris.md2", "skin": 4 }) = monster_soldier_ss : "SS Soldier" [] +@PointClass base(Monsters) size(-32 -32 -16, 32 32 72) model({ "path": ":models/monsters/tank/tris.md2" }) = monster_tank : "Tank" [] +@PointClass base(Monsters) size(-32 -32 -16, 32 32 72) model({ "path": ":models/monsters/tank/tris.md2", "skin": 2 }) = monster_tank_commander : "Tank Commander" [] +@PointClass base(Monsters) size(-64 -64 0, 64 64 72) model({ "path": ":models/monsters/boss1/tris.md2" }) = monster_supertank : "Super Tank Boss" [] + +// using a "wait" value of -1 on a path corner causes a func_train to go silent between +// itself and the next path corner when the train is restarted. The train's sound will +// resume as soon as it reaches a path corner with a "wait" value other than -1 +@PointClass base(Appearflags, Targetname) color(128 76 0) size(-8 -8 -8, 8 8 8) = path_corner : "Path marker" +[ + spawnflags(Flags) = + [ + 1 : "Teleport" : 0 + ] + target(string) : "Next path target" + pathtarget(string) : "Event to trigger" + wait(choices) : "Wait" : 0 = + [ + -1 : "Wait for retrigger" + ] +] + +// "target" doesn't work (for now)...a separate trigger is needed +@PointClass base(Appearflags, Targetname, Target) color(128 76 9) size(-8 -8 -8, 8 8 8) = point_combat : "1st point of combat" +[ + spawnflags(Flags) = + [ + 1 : "Hold" : 0 + ] +] + +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_blaster : "Blaster" +[ + spawnflags(Flags) = + [ + 1 : "No Trail" : 0 + 2 : "No Effects" : 0 + ] + dmg(integer) : "Damage" : 15 + speed(integer) : "Speed" : 1000 +] + +// set "map" value to "mapname$playername" where playername equals +// the targetname of a corresponding info_player_start in the +// next map. To play a cinematic before starting the level, the +// "map" value should be "cinemeatic.cin+mapname$playername". Note +// that a playername is not required if the corresponding info_player_start +// doesn't have a targetname. If you want this to be designated as the last +// level of a unit, place an asterix (*) before the map name. +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_changelevel : "Change level" +[ + map(string) : "Next map" +] + +// 0221 - added "_minlight" key +@SolidClass base(Appearflags, Targetname) color(0 0 255) = target_character : "Use with target_string and func_clock" +[ + team(string) : "Team" + count(integer) : "Position in the string" + _minlight(string) : "Minimum light (optional)" +] + +@PointClass base(Appearflags, Targetname, Target) color(128 128 128) size(-8 -8 -8, 8 8 8) = target_crosslevel_trigger : "Cross-level trigger" +[ + spawnflags(Flags) = + [ + 1 : "Trigger 1" : 0 + 2 : "Trigger 2" : 0 + 4 : "Trigger 3" : 0 + 8 : "Trigger 4" : 0 + 16 : "Trigger 5" : 0 + 32 : "Trigger 6" : 0 + 64 : "Trigger 7" : 0 + 128 : "Trigger 8" : 0 + ] + killtarget(string) : "Kill Target" + message(string) : "Message" + delay(integer) : "Trigger delay" +] + +@PointClass base(Appearflags, Targetname, Target) color(128 128 128) size(-8 -8 -8, 8 8 8) = target_crosslevel_target : "Cross-level trigger" +[ + spawnflags(Flags) = + [ + 1 : "Trigger 1" : 0 + 2 : "Trigger 2" : 0 + 4 : "Trigger 3" : 0 + 8 : "Trigger 4" : 0 + 16 : "Trigger 5" : 0 + 32 : "Trigger 6" : 0 + 64 : "Trigger 7" : 0 + 128 : "Trigger 8" : 0 + ] + killtarget(string) : "Kill Target" + delay(integer) : "Trigger delay (if activated)" : 1 +] + +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_earthquake : "Level wide earthquake" +[ + speed(integer) : "Severity of quake" : 200 + count(integer) : "Duration" : 5 +] + +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_explosion : "Explosion" +[ + delay(integer) : "Delay before explosion" + dmg(integer) : "Radius damage" : 0 +] + +@PointClass base(Appearflags, Targetname) color(255 0 255) size(-8 -8 -8, 8 8 8) = target_goal : "Counts a goal completed" [] + +@PointClass base(Appearflags, Targetname) color(255 0 255) size(-8 -8 -8, 8 8 8) = target_help : "Computer help message" +[ + spawnflags(Flags) = + [ + 1 : "Main Onjective" : 0 + ] + message(string) : "Computer message" +] + +// if no color spawnflags are set, the laser color defaults to dim gray (and hard to see +// setting the damage to 0 makes it use the default damage of 1 +// setting the damage to a negative number will actually give health +@PointClass base(Appearflags, Targetname, Target) color(0 128 204) size(-8 -8 -8, 8 8 8) = target_laser : "Laser" +[ + spawnflags(Flags) = + [ + 1 : "Start On" : 0 + 2 : "Red" : 0 + 4 : "Green" : 0 + 8 : "Blue" : 0 + 16 : "Yellow" : 0 + 32 : "Orange" : 0 + 64 : "Fat" : 0 + ] + dmg(integer) : "Damage" +] + +// 0221 - added "target" key +@PointClass base(Appearflags, Targetname, Target) color(0 128 204) size(-8 -8 -8, 8 8 8) = target_lightramp : "Light ramp" +[ + spawnflags(Flags) = + [ + 1 : "Toggle" : 0 + ] + speed(integer) : "Speed" + message(string) : "start/end light level" +] + +@PointClass base(Appearflags, Targetname) color(255 0 255) size(-8 -8 -8, 8 8 8) = target_secret : "Counts a secret found" +[ + message(string) : "Message to print" : "You have found a secret." +] + +// set speed and angle, otherwise spawned object drops +// +// 0221 - changed "target" key description for clarity +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_spawner : "Monster/Item spawner" +[ + target(string) : "Monster/Item to spawn" + speed(integer) : "Speed" +] + +// looped sounds are automatically volume 1, attenuation 3 :\ +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_speaker : "Sound player" +[ + spawnflags(Flags) = + [ + 1 : "Looped On" : 0 + 2 : "Looped Off" : 0 + 4 : "Reliable" : 0 + ] + noise(string) : "Sound (path/file.wav)" + attenuation(Choices) : "Attenuation" : 1 = + [ + -1 : "None, send to whole level" + 1 : "Normal fighting sounds" + 2 : "Idle sound level" + 3 : "Ambient sound level" + ] + volume(integer) : "Volume (0.0 - 1.0)" : 1 +] + +// "sounds" values other than 1 are silent. leaving in the other +// options for availability to mods/fixes +// +// 0221 - clarified "count" description +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_splash : "Creates a splash when used" +[ + sounds(choices) : "Type of splash" : 2 = + [ + 1 : "Sparks" + 2 : "Blue water" + 3 : "Brown water" + 4 : "Slime" + 5 : "Lava" + 6 : "Blood" + ] + count(integer) : "Number of pixels in splash (1 - 255)" + dmg(integer) : "Radius damage" +] + +// 0221 - removed "message" key (?) +@PointClass base(Appearflags, Targetname) color(0 0 255) size(-8 -8 -8, 8 8 8) = target_string : "String" +[ + team(string) : "Team" +] + +// eye candy... Particles #2 (style 22) is quite cool +@PointClass base(Appearflags, Targetname) color(255 0 0) size(-8 -8 -8, 8 8 8) = target_temp_entity : "Temp entity" +[ + style(choices) : "Style" : 22 = + [ + 20 : "Green Fireball" + 21 : "Particles #1" + 22 : "Particles #2" + ] +] + +// 0221 - added "delay" and "killtarget" keys +@PointClass base(Appearflags, Target) color(128 128 128) size(-8 -8 -8, 8 8 8) = trigger_always : "Always triggers" +[ + killtarget(string) : "Kill Target" + delay(integer) : "Time before triggering" +] + +@SolidClass base(Appearflags, Targetname, Target) color(128 128 128) = trigger_counter : "Counter" +[ + spawnflags(Flags) = + [ + 1 : "No Message" : 0 + ] + count(integer) : "Count before trigger" : 2 +] + +@PointClass base(Appearflags, Targetname, Target) color(76 25 153) = trigger_elevator : "Elevator trigger" [] + +@SolidClass base(Appearflags) color(128 128 128) = trigger_gravity : "Change gravity" +[ + gravity(integer) : "Gravity (standard = 1.0)" : 1 +] + +@SolidClass base(Appearflags, Targetname) color(128 128 128) = trigger_hurt : "Hurts on touch" +[ + spawnflags(Flags) = + [ + 1 : "Start Off" : 0 + 2 : "Toggle" : 0 + 4 : "Silent" : 0 + 8 : "No Protection" : 0 + 16 : "Slow hurt" : 0 + ] + dmg(integer) : "Damage" : 5 +] + +@PointClass base(Appearflags, Targetname, Target) color(128 128 128) size(-8 -8 -8, 8 8 8) = trigger_key : "Triggers with key" +[ + killtarget(string) : "Kill target" + item(string) : "Item classname" : "key_blue_key" +] + +@SolidClass base(Appearflags) color(128 128 128) = trigger_monsterjump : "Makes monsters jump" +[ + speed(integer) : "Speed thrown forward" : 200 + height(integer) : "Height thrown upward" : 200 +] + +// 0221 - switched around _relay, _once, and _multiple +@PointClass base(Appearflags, Targetname, Target) color(128 128 128) = trigger_relay : "Relay trigger" +[ + killtarget(string) : "Kill Target" + delay(integer) : "Time before triggering" + message(string) : "Trigger message" +] + +// 0303 - removed "sounds" key +@SolidClass base(trigger_relay) = trigger_once : "Single fire trigger" +[ + spawnflags(Flags) = + [ + 4 : "Triggered" : 0 + ] +] + +@SolidClass base(trigger_once) = trigger_multiple : "Multiple fire trigger" +[ + spawnflags(Flags) = + [ + 1 : "Monster" : 0 + 2 : "Not Player" : 0 + ] + wait(integer) : "Seconds between triggers" : 0 +] + +@SolidClass base(Appearflags) color(128 128 128) = trigger_push : "Push trigger" +[ + spawnflags(Flags) = + [ + 1 : "Push Once" : 0 + ] + speed(integer) : "Speed of push" : 1000 +] + +// 0221 - added "_minlight" key to _breach and _base +@SolidClass base(Appearflags, Targetname, Target) color(128 255 128) = turret_breach : "Turret breach" +[ + speed(integer) : "Speed" : 50 + dmg(integer) : "Damage" : 10 + minpitch(integer) : "Miminum pitch angle" : -30 + maxpitch(integer) : "Maximum pitch angle" : 30 + minyaw(integer) : "Minimum yaw angle" : 0 + maxyaw(integer) : "Maximum yaw angle" : 360 + team(string) : "Team" + _minlight(string) : "Minimum light (optional)" +] +@SolidClass base(Appearflags) color(128 255 128) = turret_base : "Turret base" +[ + team(string) : "Team" + _minlight(string) : "Minimum light (optional)" +] +@PointClass base(Appearflags) color(128 255 128) size(-16 -16 -24, 16 16 32) model({ "path": ":models/monsters/infantry/tris.md2"}) = turret_driver : "Turret driver" [ target(string) : "Target (turret_breach)" ] +@PointClass base(Appearflags) color(0 128 204) size(-8 -8 -8, 8 8 8) = viewthing : "Just for debugging level - dont use" [] +@BaseClass base(Appearflags, Target) color(76 76 255) size(-16 -16 -16, 16 16 16) = Weapons +[ + team(string) : "Team" +] + +// +// Weapons! +// + +@PointClass base(Weapons) model({ "path": ":models/weapons/g_shotg/tris.md2" }) = weapon_shotgun : "Shotgun" [] +@PointClass base(Weapons) model({ "path": ":models/weapons/g_shotg2/tris.md2" }) = weapon_supershotgun : "Super shotgun" [] +@PointClass base(Weapons) model({ "path": ":models/weapons/g_machn/tris.md2" }) = weapon_machinegun : "Machinegun" [] +@PointClass base(Weapons) model({ "path": ":models/weapons/g_chain/tris.md2" }) = weapon_chaingun : "Chain gun" [] +@PointClass base(Weapons) model({ "path": ":models/weapons/g_launch/tris.md2" }) = weapon_grenadelauncher : "Grenade launcher" [] +@PointClass base(Weapons) model({ "path": ":models/weapons/g_rocket/tris.md2" }) = weapon_rocketlauncher : "Rocket launcher" [] +@PointClass base(Weapons) model({ "path": ":models/weapons/g_hyperb/tris.md2" }) = weapon_hyperblaster : "Hyperblaster" [] +@PointClass base(Weapons) model({ "path": ":models/weapons/g_rail/tris.md2" }) = weapon_railgun : "Rail gun" [] +@PointClass base(Weapons) model({ "path": ":models/weapons/g_bfg/tris.md2" }) = weapon_bfg : "Big Freakin Gun!" [] diff --git a/tools/trenchbroom/games/Quake2/colormap.pcx b/tools/trenchbroom/games/Quake2/colormap.pcx new file mode 100644 index 0000000..857c041 Binary files /dev/null and b/tools/trenchbroom/games/Quake2/colormap.pcx differ diff --git a/tools/trenchbroom/games/Quake3/GameConfig.cfg b/tools/trenchbroom/games/Quake3/GameConfig.cfg new file mode 100644 index 0000000..5bdcae0 --- /dev/null +++ b/tools/trenchbroom/games/Quake3/GameConfig.cfg @@ -0,0 +1,129 @@ +{ + "version": 9, + "name": "Quake 3", + "icon": "Icon.png", + "experimental": true, + "fileformats": [ +// brush primitives not yet implemented +// { "format": "Quake3" }, + { "format": "Quake3 (Valve)" }, + { "format": "Quake3 (legacy)" } + ], + "filesystem": { + "searchpath": "baseq3", + "packageformat": { "extension": ".pk3", "format": "zip" } + }, + "materials": { + "root": "textures", + "extensions": [ ".tga", ".png", ".jpg", ".jpeg" ], + "shaderSearchPath": "scripts" // this will likely change when we get a material system + }, + "entities": { + "definitions": [ "entities.ent" ], + "defaultcolor": "0.6 0.6 0.6 1.0", + "scale": [ modelscale, modelscale_vec ] // this is an expression that is evaluated at runtime + }, + "tags": { + "brush": [ + { + "name": "Trigger", + "attribs": [ "transparent" ], + "match": "classname", + "pattern": "trigger_*", + "material": "common/trigger" + } + ], + "brushface": [ + { + "name": "Clip", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "common/*clip" + }, + { + "name": "Caulk", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "common/*caulk" + }, + { + "name": "Hint", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "common/hint*" + }, + { + "name": "Detail", + "match": "contentflag", + "flags": [ "detail" ] + }, + { + "name": "Liquid", + "match": "surfaceparm", + "pattern": [ "water", "lava", "slime" ] + }, + { + "name": "Translucent", + "attribs": [ "transparent" ], + "match": "surfaceparm", + "pattern": [ "trans", "fog" ] + }, + { + "name": "Areaportal", + "attribs": [ "transparent" ], + "match": "surfaceparm", + "pattern": [ "areaportal" ] + }, + { + "name": "Clusterportal", + "attribs": [ "transparent" ], + "match": "surfaceparm", + "pattern": [ "clusterportal" ] + } + ] + }, + "faceattribs": { + "defaults": { + "scale": [0.5, 0.5] + }, + "surfaceflags": [], + "contentflags": [ + { "unused": true }, // 1 + { "unused": true }, // 2 + { "unused": true }, // 4 + { "unused": true }, // 8 + { "unused": true }, // 16 + { "unused": true }, // 32 + { "unused": true }, // 64 + { "unused": true }, // 128 + { "unused": true }, // 256 + { "unused": true }, // 512 + { "unused": true }, // 1024 + { "unused": true }, // 2048 + { "unused": true }, // 4096 + { "unused": true }, // 8192 + { "unused": true }, // 16384 + { "unused": true }, // 32768 + { "unused": true }, // 65536 + { "unused": true }, // 131,072 + { "unused": true }, // 262,144 + { "unused": true }, // 524,288 + { "unused": true }, // 1,048,576 + { "unused": true }, // 2,097,152 + { "unused": true }, // 4,194,304 + { "unused": true }, // 8,388,608 + { "unused": true }, // 16,777,216 + { "unused": true }, // 33,554,432 + { "unused": true }, // 67,108,864 + { + "name": "detail", + "description": "Detail brush" + } // 134,217,728 + ] + }, + "softMapBounds":"-65536 -65536 -65536 65536 65536 65536", + "compilationTools": [ + { "name": "q3map2", "description": "Path to your q3map2 executable, which performs the main bsp/vis/light compilation phases" }, + { "name": "bspc", "description": "Path to your bspc or mbspc executable, which creates .aas files for bot support" } + ] +} diff --git a/tools/trenchbroom/games/Quake3/Icon.png b/tools/trenchbroom/games/Quake3/Icon.png new file mode 100644 index 0000000..8a22ef3 Binary files /dev/null and b/tools/trenchbroom/games/Quake3/Icon.png differ diff --git a/tools/trenchbroom/games/Quake3/entities.ent b/tools/trenchbroom/games/Quake3/entities.ent new file mode 100644 index 0000000..406fdca --- /dev/null +++ b/tools/trenchbroom/games/Quake3/entities.ent @@ -0,0 +1,2465 @@ + + + + + + +-------- KEYS -------- +The name of the entity targeted for projection. +-------- NOTES -------- +Compiler-only entity that specifies a decal to be projected. Should contain 1 or more patch meshes (curves) and target an info_null entity. Patch mesh should be using a shader with "polygonoffset" (or other blending methods) or z-fighting will occur. The distance between the center of the _decal entity and the target is the axis and distance of projection. + + + +-------- KEYS -------- +Rotation angle of the sky surfaces. +Individual control of PITCH, YAW, and ROLL (default 0 0 0). +Scaling factor (default 64), good values are between 50 and 300, depending on the map. +-------- NOTES -------- +Compiler-only entity that specifies the origin of a skybox (a wholly contained, separate area of the map), similar to some games portal skies. When compiled with Q3Map2, the skybox surfaces will be visible from any place where sky is normally visible. It will cast shadows on the normal parts of the map, and can be used with cloud layers and other effects. + + + + + +BFG ammo. Gives the player 15 by default. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 40, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of ammo given to the player when picked up (default 15). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + + +Machine Gun ammo. Gives the player 50 by default. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 40, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of ammo given to the player when picked up (default 50). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Plasma Gun ammo. Gives the player 30 by default. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 40, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of ammo given to the player when picked up (default 30). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Grenade Launcher ammo. Gives the player 5 by default. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 40, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of ammo given to the player when picked up (default 5). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Lightning Gun ammo. Gives the player 60 by default. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 40, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of ammo given to the player when picked up (default 60). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, when set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Rocket Launcher ammo. Gives the player 5 by default. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 40, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of ammo given to the player when picked up (default 5). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Shotgun ammo. Gives the player 10 by default. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 40, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of ammo given to the player when picked up (default 10). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Railgun ammo. Gives the player 10 by default. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 40, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of ammo given to the player when picked up (default 10). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Solid entity that oscillates back and forth in a linear motion. By default, it will have an amount of displacement in either direction equal to the dimension of the brush in the axis in which it's bobbing. Entity bobs on the Z axis (up-down) by default. It can also emit sound if the "noise" key is set. Will crush the player when blocked. +-------- KEYS -------- +Amount of time in seconds for one complete oscillation cycle (default 4). +Sets the amount of travel of the oscillation movement (default 32). +Sets the start offset of the oscillation cycle. Values must be 0 < phase < 1. Any integer phase value is the same as no offset (default 0). +Path/name of .wav file to play. Use looping sounds only (e.g. sound/world/drone6.wav - see notes). +Path/name of model to include (.md3 files only, e.g. models/mapobjects/jets/jets01.md3). +Diameter of constant light of .md3 model, included with entity (default 0, range 0 - 1024). +Color of constant light of .md3 model, included with entity (default 1 1 1). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +-------- Q3MAP2 KEYS -------- +Used to attach a misc_model entity to this entity. +Floating point value, scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0). +Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. +Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. +Sets the cel shader used for this geometry. Note: Omit the "textures/" prefix. +-------- Q3MAP2 TERRAIN KEYS -------- +Path/name for the art file used to guide the mapping of textures on the terrain surface. +Number of unique root shaders that will be used on the terrain. +Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix. +-------- SPAWNFLAGS -------- +Entity will bob along the X axis. +Entity will bob along the Y axis. +-------- NOTES -------- +In order for the sound to be emitted from the entity, it is recommended to include a brush with an origin shader at its center, otherwise the sound will not follow the entity as it moves. When using the model2 key, the origin point of the model will correspond to the origin point defined by the origin brush. + +Target this entity with a misc_model to have the model attached to the entity (set the model's "target" key to the same value as this entity's "targetname"). + + + + + +When a button is touched by a player, it moves in the direction set by the "angle" key, triggers all its targets, stays pressed by an amount of time set by the "wait" key, then returns to it's original position where it can be operated again. +-------- KEYS -------- +Determines the direction in which the button will move (up = -1, down = -2). +Pitch and yaw moving direction angles of button (default 0 0). The roll angle does not apply. +All entities with a matching targetname will be triggered. +If set, other entities can be used to activate the button along with touch or damage way of doing this. +Speed of button's displacement (default 40, -1 = reach the end of move instantly). +Number of seconds button stays pressed (default 1, -1 = return immediately). +Lip remaining at end of move. Default value is 4, which results in 2u of physical lip. I.e. for wished amount of move set key to [size + 2 - amount], 2 for full move, [size + 2] for none. +If set to any non-zero value, the button must take damage (any amount) to activate (default 0). +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +Path/name of model to include (.md3 files only, e.g. models/mapobjects/pipe/pipe02.md3). +Diameter of constant light of .md3 model, included with entity (default 0, range 0 - 1024). +Color of constant light of .md3 model, included with entity (default 1 1 1). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- Q3MAP2 KEYS -------- +Used to attach a misc_model entity to this entity. +Floating point value, scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0). +Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. +Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. +Sets the cel shader used for this geometry. Note: Omit the "textures/" prefix. +-------- Q3MAP2 TERRAIN KEYS -------- +Path/name for the art file used to guide the mapping of textures on the terrain surface. +Number of unique root shaders that will be used on the terrain. +Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix. +-------- NOTES -------- +When using the model2 key, the origin point of the model will correspond to the origin point defined by the origin brush. + +Target this entity with a misc_model to have the model attached to the entity (set the model's "target" key to the same value as this entity's "targetname"). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Normal sliding door entity. By default, the door will activate when player walks close to it or when damage is inflicted to it. +-------- KEYS -------- +Determines the opening direction of door (up = -1, down = -2). +Pitch and yaw opening direction angles of door (default 0 0). The roll angle does not apply. +All entities with a matching targetname will be triggered. +If set, a func_button or trigger is required to activate the door (unless using health key). +Determines how fast the door moves (default 400, -1 = reach the end of move instantly). +Number of seconds before door returns (default 2, -1 = return immediately) +Lip remaining at end of move. Default value is 8, which results in 6u of physical lip. I.e. for wished amount of move set key to [size + 2 - amount], 2 for full move, [size + 2] for none. +If set to any non-zero value, the door must take damage (any amount) to activate (default 0). +Damage to inflict on player when he blocks operation of door (default 2). Door will reverse direction when blocked unless CRUSHER spawnflag is set. +Assign the same team name to multiple doors that should operate together (see notes). +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +Path/name of model to include (.md3 files only, e.g. models/mapobjects/pipe/pipe02.md3). +Diameter of constant light of .md3 model, included with entity (default 0, range 0 - 1024). +Color of constant light of .md3 model, included with entity (default 1 1 1). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- Q3MAP2 KEYS -------- +Used to attach a misc_model entity to this entity. +Floating point value scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0). +Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. +Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. +Sets the cel shader used for this geometry. Note: Omit the "textures/" prefix. +-------- Q3MAP2 TERRAIN KEYS -------- +Path/name for the art file used to guide the mapping of textures on the terrain surface. +Number of unique root shaders that will be used on the terrain. +Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix. +-------- SPAWNFLAGS -------- +The door will spawn in the open state and operate in reverse. +Door will not reverse direction when blocked and will keep damaging player until he dies or gets out of the way. +-------- NOTES -------- +Unlike in Quake 2, doors that touch are NOT automatically teamed. If you want doors to operate together, you have to team them manually by assigning the same team name to all of them. When using the model2 key, the origin point of the model will correspond to the origin point defined by the origin brush. + +Target this entity with a misc_model to have the model attached to the entity (set the model's "target" key to the same value as this entity's "targetname"). Note: func_door and func_plat targeted by a misc_model will also require a trigger_* entity with the same target key/value as the model. + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +This is not an entity as such. It is strictly an editor utility to group world brushes and patches together for convenience (selecting, moving, copying, applying special compilation parameters etc). You cannot group entities with this. Func_group contents is merged into worldspawn entity during compilation process. + +-------- Q3MAP2 KEYS -------- +Floating point value, scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0). +Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. +Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. +Sets the cel shader used for this geometry. Note: Omit the "textures/" prefix. +-------- Q3MAP2 TERRAIN KEYS -------- +Path/name for the art file used to guide the mapping of textures on the terrain surface. +Number of unique root shaders that will be used on the terrain. +Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix. +-------- NOTES -------- +To make a func_group into a terrain entity, refer to the Terrain Construction documentation. + + + + + +Solid entity that describes a pendulum back and forth rotation movement. Rotates on the X axis by default. Pendulum frequency is a physical constant based on the height of the entity and gravity. Blocking the pendulum instantly kills a player. +-------- KEYS -------- +Angle offset of axis of rotation from default X axis (default 0). +Pitch, yaw and roll offsets of axis of rotation from default X axis (default 0 0 0). +Angle of swing arc in either direction from initial position (default 30). +Sets the start offset of the swinging cycle. Values must be 0 < phase < 1. Any integer phase value is the same as no offset (default 0). +Path/name of .wav file to play. Use looping sounds only (e.g. sound/world/drone6.wav). +Path/name of model to include (.md3 files only, e.g. models/mapobjects/jets/jets01.md3). +Diameter of constant light of .md3 model, included with entity (default 0, range 0 - 1024). +Color of constant light of .md3 model, included with entity (default 1 1 1). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- Q3MAP2 KEYS -------- +Used to attach a misc_model entity to this entity. +Floating point value, scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0). +Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. +Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. +Sets the cel shader used for this geometry. Note: Omit the "textures/" prefix. +-------- Q3MAP2 TERRAIN KEYS -------- +Path/name for the art file used to guide the mapping of textures on the terrain surface. +Number of unique root shaders that will be used on the terrain. +Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix. +-------- NOTES -------- +You need to have an origin brush as part of this entity. The center of that brush will be the point through which the rotation axis passes. When using the model2 key, the origin point of the model will correspond to the origin point defined by the origin brush. + +Target this entity with a misc_model to have the model attached to the entity (set the model's "target" key to the same value as this entity's "targetname"). + + + + + +Rising platform the player can ride to reach higher places. Plats must always be drawn in the raised position, so they will operate and be lighted correctly but they spawn in the lowered position (which equals to behavior of func_door with START_OPEN flag set). The plat will stay in the raised position until the player steps off. +-------- KEYS -------- +Determines how fast the plat moves (default 200, -1 = reach the end of move instantly). +Lip remaining at start of move. Default value is 8, which results in 6u of physical lip. I.e. for wished amount of move set key to [size + 2 - amount], 2 for full move, [size + 2] for none. Has no effect if "height" is set. +Sets the total amount of vertical travel of the plat. It's convenient alternative to "lip" key (overrides one). +Damage to inflict on player when he blocks operation of plat (default 2). Plat will reverse direction when blocked. +All entities with a matching targetname will be triggered. +If set, the trigger that points to this will raise the plat each time it fires. The plat raises and comes back down a second later if no player is on it. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +Path/name of model to include (.md3 files only, e.g. models/mapobjects/pipe/pipe02.md3). +Diameter of constant light of .md3 model, included with entity (default 0, range 0 - 1024). +Color of constant light of .md3 model, included with entity (default 1 1 1). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- Q3MAP2 KEYS -------- +Used to attach a misc_model entity to this entity. +Floating point value, scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0). +Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. +Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. +Sets the cel shader used for this geometry. Note: Omit the "textures/" prefix. +-------- Q3MAP2 TERRAIN KEYS -------- +Path/name for the art file used to guide the mapping of textures on the terrain surface. +Number of unique root shaders that will be used on the terrain. +Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix. +-------- NOTES -------- +May also be descending platform with negative "height" or according "lip" keys set. + +When using the model2 key, the origin point of the model will correspond to the origin point defined by the origin brush. + +Target this entity with a misc_model to have the model attached to the entity (set the model's "target" key to the same value as this entity's "targetname"). Note: func_door and func_plat targeted by a misc_model will also require a trigger_* entity with the same target key/value as the model. + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Solid entity that rotates continuously. Rotates on the Z axis by default and requires an origin brush. It will always start on in the game and is not targetable. +-------- KEYS -------- +Determines how fast entity rotates (default = 100 degrees per second). +Path/name of .wav file to play. Use looping sounds only (e.g. sound/world/drone6.wav). +Path/name of model to include (.md3 files only, e.g. models/mapobjects/bitch/fembotbig.md3). +Diameter of constant light of .md3 model, included with entity (default 0, range 0 - 1024). +Color of constant light of .md3 model, included with entity (default 1 1 1). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- Q3MAP2 KEYS -------- +Used to attach a misc_model entity to this entity. +Floating point value, scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0). +Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. +Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. +Sets the cel shader used for this geometry. Note: Omit the "textures/" prefix. +-------- Q3MAP2 TERRAIN KEYS -------- +Path/name for the art file used to guide the mapping of textures on the terrain surface. +Number of unique root shaders that will be used on the terrain. +Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix. +-------- SPAWNFLAGS -------- +Entity will rotate along the X axis. +Entity will rotate along the Y axis. +-------- NOTES -------- +You need to have an origin brush as part of this entity. The center of that brush will be the point through which the rotation axis passes. It will rotate along the Z axis by default. You can check either the X_AXIS or Y_AXIS box to change that. When using the model2 key, the origin point of the model will correspond to the origin point defined by the origin brush. + +Target this entity with a misc_model to have the model attached to the entity (set the model's "target" key to the same value as this entity's "targetname"). + + + + + +Static bspmodel. Can be used for conditional walls and models. +-------- KEYS -------- +Path/name of model to include (.md3 files only, e.g. models/mapobjects/bitch/fembotbig.md3). +Diameter of constant light of .md3 model, included with entity (default 0, range 0 - 1024). +Color of constant light of .md3 model, included with entity (default 1 1 1). +NOT SUPPORTED BY RENDERER - if set, a func_button or trigger can make entity disappear from the game (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- Q3MAP2 KEYS -------- +Used to attach a misc_model entity to this entity. +Floating point value, scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0). +Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. +Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. +Sets the cel shader used for this geometry. Note: Omit the "textures/" prefix. +-------- Q3MAP2 TERRAIN KEYS -------- +Path/name for the art file used to guide the mapping of textures on the terrain surface. +Number of unique root shaders that will be used on the terrain. +Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix. +-------- NOTES -------- +When using the model2 key, the origin point of the model will correspond to the origin point defined by the origin brush. If a model is included with a targeted func_static, the brush(es) of the entity will be removed from the game but the .md3 model won't: It will automatically be moved to the (0 0 0) world origin so you should NOT include an .md3 model to a targeted func_static. + +Because the map has only a single bot navigation file, func_static cannot be used to make significant changes in game play flow between differing game types. + +Target this entity with a misc_model to have the model attached to the entity (set the model's "target" key to the same value as this entity's "targetname"). + + + + + +Time delay trigger that will continuously fire its targets after a preset time delay. The time delay can also be randomized. When triggered, the timer will toggle on/off. +-------- KEYS -------- +Delay in seconds between each triggering of its targets (default 1). +Random time variance in seconds added or subtracted from "wait" delay (default 1 - see notes). +This points to the entities to trigger. +A func_button or trigger that points to this will toggle the timer on/off when activated. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- SPAWNFLAGS -------- +Timer will start on in the game and continuously fire its targets. +-------- NOTES -------- +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Trains are moving solids that follow a looped string of path_corner entities. Trains in Q3A are very basic, they also require an origin brush (see notes). +-------- KEYS -------- +Speed of displacement of train (default 100 or overridden by speed value of path). +This points to the first path_corner of the path which is also the spawn location of the train's origin. +Path/name of model to include (.md3 files only, e.g. models/mapobjects/pipe/pipe02.md3). +Diameter of constant light of .md3 model, included with entity (default 0, range 0 - 1024). +Color of constant light of .md3 model, included with entity (default 1 1 1). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- Q3MAP2 KEYS -------- +Used to attach a misc_model entity to this entity. +Floating point value, scaling the resolution of lightmaps on brushes/patches in this entity (default 1.0). +Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. +Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. +Sets the cel shader used for this geometry. Note: Omit the "textures/" prefix. +-------- Q3MAP2 TERRAIN KEYS -------- +Path/name for the art file used to guide the mapping of textures on the terrain surface. +Number of unique root shaders that will be used on the terrain. +Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix. +-------- NOTES -------- +1. Trains always start on in the game. +2. Trains do not damage the played when blocked. +3. Trains cannot emit sound. +4. Trains are not triggerable or toggle-able. +5. Trains cannot be block-stopped just by getting in their way, the player must be wedged between the train and another obstacle to block it. + +You need to have an origin brush as part of this entity. When using the model2 key, the origin point of the model will correspond to the origin point defined by the origin brush. + +Target this entity with a misc_model to have the model attached to the entity (set the model's "target" key to the same value as this entity's "targetname"). + + + + + +Medkit that can be picked up and used later. Brings the player's health back to 100 when used. Player can only carry one holdable item at a time. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 60, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Teleporter item that can be picked up and used later. Teleports the player to a random player spawn point when used. Player can only carry one holdable item at a time. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 60, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +This attracts bots which have a camping preference in their AI characteristics. It should be placed at least 32 units away from any brush surface. +-------- KEYS -------- +Number of units that the bot can move away from camp entity while camping on it. +Number that is compared against the weight assigned to all the other camp spots in the map to determine if a bot chooses to camp there. The value is normalized against all other weight values. +-------- NOTES -------- +Examples of bots which have a high camping preference are: Razor, Tank Jr., Grunt, Patriot and Doom. Examples of bots which have a low camping preference are: Klesk, Mynx, Sarge, Keel and Xaero. + + + + + +Used as a positional target for entities that can use directional pointing. A target_position can be used instead of this but was kept in Q3A for legacy purposes. +-------- KEYS -------- +Must match the target key of entity that uses this for pointing. +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. + + + + + +Used as a positional target for light entities to create a spotlight effect. A target_position can be used instead of this but was kept in Q3A for legacy purposes. +-------- KEYS -------- +Must match the target key of entity that uses this for pointing. +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. + + + + + +Normal player spawning location for Q3A levels. +-------- KEYS -------- +Direction in which player will look when spawning in the game. Does not apply to bots. +Pitch, yaw and roll angles of sight direction. +This can point at a target_give entity for respawn freebies or to anything else to trigger. +When set to 1, bots will never use this spawn point to respawn in the game. +When set to 1, human players will never use this spawn point to respawn in the game. +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- SPAWNFLAGS -------- +Makes the spawnpoint the initial place for the player to spawn at the beginning of the game. + + + + + +Camera for intermission screen between matches. This also automatically generates the podium for bot arena matches (see notes). Can be aimed by setting the "angle", "angles" keys or by targeting an aiming entity. Use only one per level. +-------- KEYS -------- +Yaw angle of sight direction. +Alternate "pitch, yaw, roll" angles method of aiming intermission camera (default 0 0 0). +Point this to an info_notnull or target_position entity to set the camera's pointing angles. +-------- NOTES -------- +In genuine bot arena matches, the podium for the 1st, 2nd and 3rd place players at the end of the match is generated by this entity. The podium's origin will automatically be located 128 units in the direction of the camera's view and 84 units down from the y height of the view line at that point. It will also always be generated on a level plane regardless of the pointing angle of the camera so if that angle is too steep, part of the podium model might not be visible. Make sure you leave at least 106 units of free space in front of where the camera points to otherwise the podium model won't be visible at all. + + + + + +Player spawn location. It works in Quake III Arena, but it is not used in the Id maps. Use info_player_deathmatch instead. +-------- KEYS -------- +Direction in which player will look when spawning in the game. +Pitch, yaw and roll angles of sight direction. +This can point at a target_give entity for respawn freebies or to anything else to trigger. + + + + + + + + + +Red Armor - 100 points. All armor can be cumulated up to a maximum of 200 points and slowly wears out to 100 points. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 25, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Yellow Armor - 50 points. All armor can be cumulated up to a maximum of 200 points and slowly wears out to 100 points. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 25, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Green Armor Shard - 5 points. All armor can be cumulated up to a maximum of 200 points and slowly wears out to 100 points. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 25, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Game Function: An invisible entity which attracts a bot to it. Use to move bots to parts of a map that might otherwise not be used (NEW ENTITY). +-------- KEYS -------- +Non-zero floating point value, most often in the range 0 to 400. (Higher values are allowed but keep in mind that the bot should also be attracted to normal items. Don't make the weight value too high. +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The item_botroam entity can be used when a bot does not roam the whole level or prefers to go to only specific areas. This (invisible) item can be placed in a map just like regular items. Nobody can actually pick up the item it's only used to attract bots to certain places of the map. The value is the weight of the roam_item is relative to the weight assigned other items in the map (each bot has its own weights). The bot character specific item weights are stored with the bot characters AI files ("botname"_i.c for items and "botname"_w.c for weapons) in the botfiles/bots/ sub-folder in the .pk3 file. + + + + + +Battle Suit power-up - Gives protection against slime, lava and weapon splash damage. Lasts 30 seconds. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 120, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Time in seconds power-up will last when picked up (default 30). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Flight power-up. Lasts 60 seconds. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 120, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Time in seconds power-up will last when picked up (default 60). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Speed power-up. Makes player run at double speed for 30 seconds. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 120, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Time in seconds power-up will last when picked up (default 30). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Yellow cross bubble - 25 Health. Cannot be picked up over 100 health. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 35, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of health points given to the player when item is picked up (default 25). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Gold cross bubble - 50 Health. Cannot be picked up over 100 health. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 35, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of health points given to the player when item is picked up (default 50). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Blue M bubble - 100 Health. Adds 100 health points to current health up to a maximum of 200. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 40, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of health points given to the player when item is picked up (default 100). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Green cross bubble - 5 Health. Can be picked up over 100 health but slowly wears out to 100 afterwards. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 35, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of health points given to the player when item is picked up (default 5). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Invisibility power-up. Lasts 30 seconds. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 120, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Time in seconds power-up will last when picked up (default 30). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Quad Damage power-up. Lasts 30 seconds. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 120, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Time in seconds power-up will last when picked up (default 30). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Health Regeneration power-up. This will boost your current health by 5 points every second for a period of up to 30 seconds or up to 200 points whichever comes first. Afterwards, any health points over 100 slowly wears out to 100. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 120, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Time in seconds power-up will last when picked up (default 30). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Non-displayed point light source. The -pointscale and -scale arguments to Q3Map2 affect the brightness of these lights. The -skyscale argument affects brightness of entity sun lights. +-------- Q3MAP2 KEYS -------- +Overrides the default 300 intensity. Negative values may be used for negative lights. +Weighted RGB value of light color (default 1.0 1.0 1.0 = white). +Lights pointed at a target (info_null / target_position) will be spotlights. +Overrides the default 64 unit radius of a spotlight at the target point. +Set this key to 1 on a spotlight to make an infinite sun light. +Fades light attenuation. Only affects linear lights. +Scales the "light" value. +Penumbra effect - distance measured in world units for point/spot lights, and degrees for suns (~0.5-3). +Penumbra effect - the number of random jitters distributed over the solid arc (~16). +Set this key to 1 to toggle on lightmap filtering. +Filters lightmaps within set radius. +Scales light attenuation. Smaller values lessens angle attenuation, larger values for sharper, more faceted lighting (default 1.0). +Light style index number associated with worldspawn light style. Values are between 1 and 31. +-------- SPAWNFLAGS -------- +Use a linear falloff. Default is inverse distance squared (more realistic). +Ignore angle attenuation. +Do not affect the lightgrid (dynamic entity lighting). + + + + + +Non-displayed point light source THAT ONLY AFFECTS ENTITIES (lightgrid). The -pointscale and -scale arguments to Q3Map2 affect the brightness of these lights. The -skyscale argument affects brightness of entity sun lights. +-------- Q3MAP2 KEYS -------- +Overrides the default 300 intensity. +Weighted RGB value of light color (default 1.0 1.0 1.0 = white). +Lights pointed at a target will be spotlights. +Overrides the default 64 unit radius of a spotlight at the target point. +Set this key to 1 on a spotlight to make an infinite sun light. +Fades light attenuation. Only affects linear lights. +Scales the "light" value. +-------- SPAWNFLAGS -------- +Use a linear falloff. Default is inverse distance squared (more realistic). +Ignore angle attenuation. +Do not affect the lightgrid (dynamic entity lighting). Setting this spawnflag will disable this light entirely. + + + + + + +Generic placeholder for inserting models to map. Model triangles are baked to BSP. +MD3, ASE, 3DS, OBJ, FM, LWO, MD2, MDC, MS3D model formats are supported. +-------- Q3MAP2 KEYS -------- +Path/name of model to use (e.g. models/mapobjects/teleporter/teleporter.md3). +Direction in which model will be oriented. +Individual control of PITCH, YAW, and ROLL (default 0 0 0). +Floating-point value used to scale a model up or down (default 1.0). +Floating-point vector used to scale a model's axes individually (default 1.0 1.0 1.0). +Used to remap textures/shaders in the model. To remap all shaders to a given shader, use "*;models/mymodel/mytexture". To remap a specific shader, use "models/mymodel/old;models/mymodel/new". Any key starting with _remap prefix will work, so if you need more remappings, create _remap2, _remap3 etc keys. +Used to attach the misc_model to a brush entity, where its "targetname" key is the same value. +Floating point value, scaling the resolution of lightmaps on this model (if model is using lightmapped shaders) (default 1.0). +Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. +Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. +Sets the cel shader used for this geometry. Note: Omit the "textures/" prefix. +Autoclip brushes thickness (default 2.0). +-------- SPAWNFLAGS -------- +in SoF2, append a _RMG_BSP suffix to shader names instead of _BSP +Clips the model for player/weapon collisions; extruding every face along most perpendicular axial direction. For use on large architectural or terrain models, not for small decorative models. +Toggles on q3map_forceMeta for lightmapped models. Converts model triangles to bsp metasurfaces. +extrude along the model face normals for clipping +extrude each surface of the model along its average axial direction ( up/down/west/east/north/south ); faces with not matching direction (or too steep) are clipped in default mode +use the color value as alpha (for terrain blending) +Don't smooth normals when importing (forces all faces planar). +extrude along the model vertex normals for clipping; accurate collisions, if normals are fine; bad ones are replaced with 45 degrees to face +pyramidal clipping brushes (4-sided); accurate collisions +for horizontal terrain; when not possible, extrude in default mode +-//- +Extrude to the max/min point of every model surface to reduce bsp size (uses axial back plane) +use axial back plane for clipping brushes to effectively reduce bsp size; might cause unwanted collisions, make sure to -debugclip; negative _clipdepth / -clipdepth limits max thickness of resulting brushes (making non-axial backplane, if hit the limit) +other possible modes of clipping: +CLIPMODEL+AXIAL_BACKPLANE +EXTRUDE_FACE_NORMALS+PYRAMIDAL_CLIP - truncated pyramid with 45 degrees sides +EXTRUDE_TERRAIN+MAX_EXTRUDE +EXTRUDE_TERRAIN+AXIAL_BACKPLANE +EXTRUDE_VERTEX_NORMALS + PYRAMIDAL_CLIP - vertex normals mode: don't check for sides, sticking outwards +PYRAMIDAL_CLIP+AXIAL_BACKPLANE - pyramid with 3 of 4 sides axial (->small bsp) +EXTRUDE_DOWNWARDS+EXTRUDE_UPWARDS +EXTRUDE_DOWNWARDS+MAX_EXTRUDE +EXTRUDE_DOWNWARDS+AXIAL_BACKPLANE +EXTRUDE_DOWNWARDS+EXTRUDE_UPWARDS+MAX_EXTRUDE +EXTRUDE_DOWNWARDS+EXTRUDE_UPWARDS+AXIAL_BACKPLANE +EXTRUDE_UPWARDS+MAX_EXTRUDE +EXTRUDE_UPWARDS+AXIAL_BACKPLANE + + + + + + +Portal camera. This camera is used to project its view onto a portal surface in the level through the intermediary of a misc_portal_surface entity. Use the "angle", "angles" keys or target a target_position or info_notnull entity to set the camera's pointing direction. +-------- KEYS -------- +Yaw aiming angle of the portal camera (default 0). +This sets the pitch and yaw aiming angles of the portal camera (default 0 0). Use "roll" key to set roll angle. +Point this to a target_position entity to set the camera's pointing direction. +A misc_portal_surface portal surface indicator must point to this. +Roll angle of camera. For axial directions a value of 0 is upside down and 180 is the same as the player's view. For other sorts of directions values of 90 and -90 may work (inconsistent math). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- SPAWNFLAGS -------- +Makes the portal camera rotate slowly along the roll axis. +Makes the portal camera rotate faster along the roll axis. +Stops the camera portal from wobbling. +-------- NOTES -------- +Both the setting "angle(s)" key or "targeting a target_position" methods can be used to aim the camera. In both cases, the "roll" key must be used to set the roll angle. If either the SLOWROTATE or FASTROTATE spawnflag is set, then the "roll" value is irrelevant. + + + + + +Portal surface indicator. This will "lock on" the brush face closest to it and identify as a portal. The view displayed on the portal surface is the view of the misc_portal_camera that this entity targets. Also used for mirrors (see notes). +-------- KEYS -------- +Point this to a misc_portal_camera that "sees" the view you want to display on the portal. +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- NOTES -------- +The entity must be no farther than 64 units away from the portal surface to lock onto it. +To make a mirror, apply the common/mirror shader to the surface, place this entity near it but don't target a misc_portal_camera. +To make a portal, you need to use a shader with "alphagen portal", for instance textures/sfx/portal_sfx. + + + + + +Teleport destination location point for trigger_teleporter and target_teleporter entities. +-------- KEYS -------- +Direction in which player will look when teleported. +Pitch, yaw and roll angles of sight direction after teleportation. +Trigger_teleporter or target_teleporter point to this. +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. + + + + + +Path corner entity that func_trains can be made to follow. +-------- KEYS -------- +Point to next path_corner in the path and optionally to an entity to trigger, when train reaches this entity. +The train following the path or the previous path_corner in the path points to this. +Speed of func_train while moving to the next path corner. This will override the speed value of the train. +Number of seconds func_train will pause on path corner before moving to next path corner (default 0 - see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- NOTES -------- +Setting the wait key to -1 will not make the train stop on the path corner, it will simply default to 0. + + + + + +This will shoot a grenade each time it's triggered. Aiming is done by setting the "angle", "angles" keys or by targeting an info_notnull, target_position or any other entity. +-------- KEYS -------- +Yaw aiming angle of shooter. +This sets the pitch and yaw aiming angles of shooter (default 0 0). The roll angle does not apply. +This points to a target_position entity for aiming the grenades. +Activating trigger points to this. +Random aiming variance in degrees (range 0 - 90, default 1 - see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- NOTES -------- +When the random key is set, its value is used to calculate a maximum angle deviation from the normal trajectory formed by a straight line between the shooter and the aiming entity it targets. The final trajectory will be a random value anywhere between no deviation at all (0) to maximum deviation (value of the random key / 2). Setting random key to 0 wont disable random, setting it to 180, 360 or 0.0000001 will do. + +Both the setting "angle(s)" key or "targeting a target_position" methods can be used to aim the shooter. + + + + + +This will shoot a plasma ball each time it's triggered. Aiming is done by setting the "angle", "angles" keys or by targeting an info_notnull, target_position or any other entity. +-------- KEYS -------- +Yaw aiming angle of shooter. +This sets the pitch and yaw aiming angles of shooter (default 0 0). The roll angle does not apply. +This points to a target_position entity for aiming the plasma balls. +Activating trigger points to this. +Random aiming variance in degrees (range 0 - 90, default 1 - see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- NOTES -------- +When the random key is set, its value is used to calculate a maximum angle deviation from the normal trajectory formed by a straight line between the shooter and the aiming entity it targets. The final trajectory will be a random value anywhere between no deviation at all (0) to maximum deviation (value of the random key / 2). Setting random key to 0 wont disable random, setting it to 180, 360 or 0.0000001 will do. + +Both the setting "angle(s)" key or "targeting a target_position" methods can be used to aim the shooter. + + + + + +This will shoot a rocket each time it's triggered. Aiming is done by setting the "angle", "angles" keys or by targeting an info_notnull, target_position or any other entity. +-------- KEYS -------- +Yaw aiming angle of shooter. +This sets the pitch and yaw aiming angles of shooter (default 0 0). The roll angle does not apply. +This points to a target_position entity for aiming the rockets. +Activating trigger points to this. +Random aiming variance in degrees (range 0 - 90, default 1 - see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- NOTES -------- +When the random key is set, its value is used to calculate a maximum angle deviation from the normal trajectory formed by a straight line between the shooter and the aiming entity it targets. The final trajectory will be a random value anywhere between no deviation at all (0) to maximum deviation (value of the random key / 2). Setting random key to 0 wont disable random, setting it to 180, 360 or 0.0000001 will do. + +Both the setting "angle(s)" key or "targeting a target_position" methods can be used to aim the shooter. + + + + + +Time delay trigger intermediary. Like a target_relay, this can only be fired by other triggers which will cause it in turn to fire its own targets. +-------- KEYS -------- +This points to entities to activate when this entity is triggered. +Activating trigger points to this. +Delay in seconds from when this gets triggered to when it fires its own targets (default 1). +Same as wait. For consistency, wait is preferred. +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- NOTES -------- +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +This is used to give ammo, weapons, health or items to the player who activates it. +-------- KEYS -------- +This points to the item(s) to give when activated. These items aren't respawned in game. +Activating trigger or spawn entity points to this. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- NOTES -------- +There are 2 ways to use this entity. +a) Automatically give items to players when they spawn in the game: Make a spawn location entity like info_player_deathmatch or CTF respawn, targeting this entity, then target it to the item(s) to give to the player upon respawn. +b) Give items to players during the game: Make a trigger_multiple/func_button/other_activatable_entity target this entity, then make it target the item(s) to give to the player when the trigger is touched. + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +This will kill the player who activates the trigger that fires this target. +-------- KEYS -------- +The activating trigger points to this. +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. + + + + + + + + + + + + + + + + + + + + +Location marker used by bots and players for team orders and team chat in the course of Teamplay games. The closest target_location in sight is used for the location. If none is in sight, the closest in distance is used. +-------- KEYS -------- +Name of the location (text string). Displayed in parentheses in front of all team chat and order messages. +Color of the location text displayed in parentheses during team chat. Set to 0-7 for color. + 0 : White (default) + 1 : Red + 2 : Green + 3 : Yellow + 4 : Blue + 5 : Cyan + 6 : Magenta + 7 : White +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. + + + + + +Aiming target for entities like light, misc_portal_camera and trigger_push (jump pads) in particular. +-------- KEYS -------- +The entity that requires an aiming direction points to this. +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- NOTES -------- +To make a jump pad, place this entity at the highest point of the jump and target it with a trigger_push entity. + + + + + +This will print a message on the center of the screen when triggered. By default, all the clients will see the message. +-------- KEYS -------- +Text string to print on screen. +The activating trigger points to this. +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- SPAWNFLAGS -------- +Only the red team players will see the message. +Only the blue team players will see the message. +Only the player that activates the target will see the message. + + + + + +This can be used to create jump pads and launch ramps. The direction of push can be set by the "angle", "angles" keys or pointing to a target_position or info_notnull entity. Unlike trigger_push, this is NOT client side predicted and must be activated by a trigger. +-------- KEYS -------- +Yaw aiming angle of push entity. +This sets the pitch and yaw aiming angles of push entity (default 0 0). The roll angle does not apply. +Speed of push (default 1000). Has no effect if entity targets an aiming entity. +This points to the aiming entity to which the player will jump. +The activating trigger points to this. Push originates from the location of the trigger. +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- SPAWNFLAGS -------- +If set, trigger will play bounce noise instead of beep noise when activated (recommended). +-------- NOTES -------- +To make a jump pad or launch ramp, create a trigger_multiple where the jump must originate. Place the target_push directly above the trigger_multiple and place the target_position entity at the highest point of the jump. Target the trigger_multiple to the target_push and target the target_push to the target_position/info_notnull (or set the target_push's "angle(s)" key). Note, that, when using aiming by target_position, it MUST be located higher, than target_push, while in "angle(s)" scenario player may be pushed downwards too. + + + + + +This can only be activated by other triggers which will cause it in turn to activate its own targets. +-------- KEYS -------- +This points to entities to activate when this entity is triggered. +Activating trigger points to this. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- SPAWNFLAGS -------- +Only red team players can activate trigger. +Only red team players can activate trigger. +One of the targeted entities will be triggered at random. + +-------- NOTES -------- +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +This takes away any and all item_* type powerups from player except health and armor (holdable_* items are not taken away either). Must be activated by a button or trigger_multiple entity. The player that activates the trigger will lose any powerup(s) currently in his possession. +-------- KEYS -------- +Activating trigger points to this. +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. + + + + + +This is used to automatically give frag points to the player who activates this. A spawn location entity like info_player_* or CTF respawn points can target this entity to give points to the player when he spawns in the game. Or a trigger can also be used to activate this. The activator of the trigger will get the points. +-------- KEYS -------- +Activating entity points to this. +Number of frag points to give to player (default 1). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. + + + + + +Sound generating entity that plays .wav files. Normal non-looping sounds play each time the target_speaker is triggered. Looping sounds can be set to play by themselves (no activating trigger) or be toggled on/off by a trigger. +-------- KEYS -------- +Path/name of .wav file to play (e.g. sound/world/growl1.wav - see notes). +Delay in seconds between each time the sound is played ("random" key must be set - see notes). +Random time variance in seconds added or subtracted from "wait" delay ("wait" key must be set - see notes). +The activating button or trigger points to this. +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- SPAWNFLAGS -------- +Sound will loop and initially start on in level (will toggle on/off when triggered). +Sound will loop and initially start off in level (will toggle on/off when triggered). +Sound will play full volume throughout the level. +Sound will play only for the player that activated the target. +-------- NOTES -------- +The path portion value of the "noise" key can be replaced by the implicit folder character "*" for triggered sounds that belong to a particular player model. For example, if you want to create a "bottomless pit" in which the player screams and dies when he falls into, you would place a trigger_multiple over the floor of the pit and target a target_speaker with it. Then, you would set the "noise" key to "*falling1.wav". The * character means the current player model's sound folder. So if your current player model is Visor, * = sound/player/visor, if your current player model is Sarge, * = sound/player/sarge, etc. This cool feature provides an excellent way to create "player-specific" triggered sounds in your levels. + +The combination of the "wait" and "random" keys can be used to play non-looping sounds without requiring an activating trigger but both keys must be used together. The value of the "random" key is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + + + + + +Activating this will teleport players to the location of the targeted misc_teleporter_dest entity. Unlike trigger_teleport, this entity must be activated by a trigger and does NOT allow client prediction of events. +-------- KEYS -------- +This must point to a misc_teleporter_dest entity. +Activating trigger points to this. +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. + + + + + +Blue team flag for CTF games. + + + + + +Initial Blue team spawning position for CTF games. This is where players spawn when they join the Blue team. +-------- KEYS -------- +Direction in which player will look when spawning in the game. +Pitch, yaw and roll angles of sight direction. +This can point at a target_give entity for respawn freebies or to anything else to trigger. + + + + + +Blue team respawning position for CTF games. This is where Blue team players respawn after they get fragged. +-------- KEYS -------- +Direction in which player will look when spawning in the game. +Pitch, yaw and roll angles of sight direction. +This can point at a target_give entity for respawn freebies or to anything else to trigger. + + + + + +Red team flag for CTF games. + + + + + +Initial Red team spawning position for CTF games. This is where players spawn when they join the Red team. +-------- KEYS -------- +Direction in which player will look when spawning in the game. +Pitch, yaw and roll angles of sight direction. +This can point at a target_give entity for respawn freebies or to anything else to trigger. + + + + + +Red team respawning position for CTF games. This is where Red team players respawn after they get fragged. +-------- KEYS -------- +Direction in which player will look when spawning in the game. +Pitch, yaw and roll angles of sight direction. +This can point at a target_give entity for respawn freebies or to anything else to trigger. + + + + + +Automatic trigger. It will fire the entities it targets as soon as it spawns in the game. +-------- KEYS -------- +This points to the entity to activate. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- NOTES -------- +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Any player that touches this will be hurt by "dmg" points of damage once per server frame (very fast). A sizzling sound is also played while the player is being hurt. +-------- KEYS -------- +Number of points of damage inflicted to player per server frame (default 5 - integer values only). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- SPAWNFLAGS -------- +Needs to be triggered (toggle) for damage +Allows trigger_hurt to be toggled on/off. +Suppresses the sizzling sound while player is being hurt. +Player will be hurt regardless of protection (see notes). +Changes the damage rate to once per second. +-------- NOTES -------- +The invulnerability power-up (item_enviro) does not protect the player from damage caused by this entity regardless of whether the NO_PROTECTION spawnflag is set or not. Triggering a trigger_hurt will have no effect if the START_OFF spawnflag is not set. A trigger_hurt always starts on in the game. + + + + + +Variable size repeatable trigger. It will fire the entities it targets when touched by player. Can be made to operate like a trigger_once entity by setting the "wait" key to -1. It can also be activated by another trigger that targets it. +-------- KEYS -------- +Time in seconds until trigger becomes re-triggerable after it's been touched (default 0.5, -1 = trigger once). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +This points to the entity to activate. +Activating trigger points to this. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- NOTES -------- +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +This is used to create jump pads and launch ramps. It MUST point to a target_position or info_notnull entity, located above trigger's origin, to work. Unlike target_push, this is client side predicted. +-------- KEYS -------- +This points to the target_position to which the player will jump. +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +-------- NOTES -------- +To make a jump pad or launch ramp, place the target_position/info_notnull entity at the highest point of the jump and target it with this entity. + + + + + +Touching this will teleport players to the location of targeted entity. Allows client side prediction of teleportation events. +-------- KEYS -------- +This must point to a misc_teleporter_dest entity. +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. + + + + + +Big Freaking Gun. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 5, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of ammo given to the player when weapon is picked up (default 20, -1 for 0 count). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Gauntlet. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 5, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Grappling Hook. Spawns in the game and works but is unskinned. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 5, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Grenade Launcher. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 5, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of ammo given to the player when weapon is picked up (default 10, -1 for 0 count). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Lightning Gun. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 5, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of ammo given to the player when weapon is picked up (default 100, -1 for 0 count). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Machine Gun. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 5, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of ammo given to the player when weapon is picked up (default 40, -1 for 0 count). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Plasma gun. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 5, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of ammo given to the player when weapon is picked up (default 50, -1 for 0 count). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Railgun. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 5, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of ammo given to the player when weapon is picked up (default 10, -1 for 0 count). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Rocket Launcher. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 5, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of ammo given to the player when weapon is picked up (default 10, -1 for 0 count). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Shotgun. +-------- KEYS -------- +Time in seconds before item respawns after being picked up (default 5, -1 = never respawn). +Random time variance in seconds added or subtracted from "wait" delay (default 0 - see notes). +Sets the amount of ammo given to the player when weapon is picked up (default 10, -1 for 0 count). +Set this to team items. Teamed items will respawn randomly after team master is picked up (see notes). +Picking up the item will trigger the entity this points to. +A target_give entity, pointed to this, gives the item to player. Activating this by other entities will make the item to respawn. +Name of the original shader to remap (see notes). +Name of the new shader to remap by (see notes). +When set to 1, entity will not spawn in "Free for all" and "Tournament" modes. +When set to 1, entity will not spawn in "Teamplay" and "CTF" modes. +When set to 1, entity will not spawn in Single Player mode (bot play mode). +Defines the gametypes that will spawn this item. Q3A values: ffa tournament single team ctf. Q3TA values: oneflag obelisk harvester teamtournament. +Used to make an item invisible for bot attraction. +-------- SPAWNFLAGS -------- +Item will spawn where it was placed in map and won't drop to the floor. +-------- NOTES -------- +The amount of time it takes for an item in the team to respawn is determined by the "wait" value of the item that was picked up previously. So if one of the items in the team has it's "wait" key set to -1 (never respawn), the random respawning cycle of the teamed items will stop after that item is picked up. + +When the random key is set, its value is used to calculate a minimum and a maximum delay. The final time delay will be a random value anywhere between the minimum and maximum values: (min delay = wait - random) (max delay = wait + random). + +When the entity activates its targets, all shaders/textures in the map that were originally the same name as the 'targetShaderName' value, will be changed to the 'targetShaderNewName' value. For example, turning a light on: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_on" +And this would turn it back off: + "targetShaderName" "textures/proto2/redlight_off" + "targetShaderNewName" "textures/proto2/redlight_off" + + + + + +Entity, which stores regular static map primitives (brushes and patches). +-------- KEYS -------- +Text to print at user logon. Used for name of level. +Path/name of looping .wav file used for level's music (e.g. music/sonic5.wav). +Gravity of level (default normal gravity: 800). +-------- Q3MAP2 KEYS -------- +Granularity of the lightgrid, created by q3map, which is used to dynamically light certain game objects, like players and items. Value is three integers separated by spaces, representing number of units between grid points in X Y Z. Default gridsize value is 64 64 128. Use larger powers of 2 to reduce BSP size and compile time on very large maps. +Map compiler splits the BSP tree along axial planes (X, Y and Z) for optimization. It does it as often, as specified in _blocksize key for respective axis (in units) (default 1024 1024 1024, 0 = disable, setting single value 'N' equals to setting 'N N N'). I.e. lower values result in more splits and vice versa. Increase the blocksize using larger powers of 2 to reduce compile times on very large maps with a low structural brush density. Maps, having flat architecture, might work better with horizontal splits disabled ('N N 0'). +Adds a constant value to overall lighting (default 0, range 0 - 255). Only recommended use is small values for cosmetic purposes, as high values will have a tendency to flatten out variations in light and shade. +RGB color value for ambient and other global light parameters (default is 1 1 1). +Minimum light value, levelwide. Uses the _color key to set color. Since it does not add unlike ambient, but overrides existing light values, affected areas will get flat constant light. Therefore use is highly not recommended! +Minimum vertex lighting, levelwide. +Minimum lightgrid (dynamic entity lighting) levelwide. +Keep light entities in the BSP. Normally stripped out by the BSP process and read from the .map file by the lighting phase. +Ignore q3map_sun/sun directives in sky shaders and ONLY use entity sun lights. +Limit on how many units the vis phase of compilation can see. Used in combination with level-wide fog, it can help reduce r_speeds on large, open maps. +Shader to use for "fog hull". Foghull shader should be a sky shader. Omit the "textures/" prefix. +Floating point value, scaling the resolution of lightmaps on brushes/patches in the world. Can be overridden in func_group (or other entities) (default 1.0). +Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. +Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. +Sets the cel shader used for this geometry. Note: Omit the "textures/" prefix. Overridable in entities. +*IMPORTANT* Replace "N" in the key "_styleNalphaGen" with an integer between 1 and 31 as your style index. Values takes standard shader waveform functions (e.g. wave sin 0.5 0.3 0.25 1.5) +*IMPORTANT* Replace "N" in the key "_styleNrgbGen" with an integer between 1 and 31 as your style index. Values take standard shader waveform functions (e.g. wave sin 0.5 0.3 0.25 1.5) +-------- Q3MAP2 TERRAIN KEYS -------- +Path/name for the art file used to guide the mapping of textures on the terrain surface. +Number of unique root shaders that will be used on the terrain. +Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix. + + diff --git a/tools/trenchbroom/games/Quetoo/GameConfig.cfg b/tools/trenchbroom/games/Quetoo/GameConfig.cfg new file mode 100644 index 0000000..e4c25a3 --- /dev/null +++ b/tools/trenchbroom/games/Quetoo/GameConfig.cfg @@ -0,0 +1,249 @@ +{ + "version": 9, + "name": "Quetoo", + "icon": "Icon.png", + "experimental": true, + "fileformats": [ + { "format": "Quake2" } + ], + "filesystem": { + "searchpath": "default", + "packageformat": { "extension": ".pk3", "format": "zip" } + }, + "materials": { + "root": "textures", + "extensions": [ ".jpg", ".png", ".tga" ], + "excludes": [ "*_nm", "*_norm", "*_local", "*_bump", "*_h", "*_height", "*_g", "*_gloss", "*_s", "*_spec", "*_glow", "*_luma" ] + }, + "entities": { + "definitions": [ "Quetoo.fgd" ], + "defaultcolor": "0.6 0.6 0.6 1.0" + }, + "tags": { + "brush": [ + { + "name": "Trigger", + "attribs": [ "transparent" ], + "match": "classname", + "pattern": "trigger_*", + "material": "common/trigger" + } + ], + "brushface": [ + { + "name": "Caulk", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "common/caulk" + }, + { + "name": "Clip", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "common/clip" + }, + { + "name": "Detail", + "match": "contentflag", + "flags": [ "detail" ] + }, + { + "name": "Dust", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "common/dust" + }, + { + "name": "Fog", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "common/fog" + }, + { + "name": "Hint", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "common/hint" + }, + { + "name": "Liquid", + "match": "surfaceparm", + "pattern": [ "water", "lava", "slime" ] + }, + { + "name": "Skip", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "common/skip" + }, + { + "name": "Sky", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "common/sky" + }, + { + "name": "Translucent", + "attribs": [ "transparent" ], + "match": "surfaceparm", + "pattern": [ "blend_33", "blend_66", "blend_100", "alpha_test", "decal", "material" ] + } + ] + }, + "faceattribs": { + "defaults": { + "scale": [0.25, 0.25] + }, + "surfaceflags": [ + { + "name": "light", + "description": "Surface emits light" + }, + { + "name": "slick", + "description": "Surface is slippery" + }, + { + "name": "sky", + "description": "Surface is sky" + }, + { + "name": "liquid", + "description": "Surface is liquid (set by quemap)" + }, + { + "name": "blend_33", + "description": "Surface is alpha blended with 33% transparency" + }, + { + "name": "blend_66", + "description": "Surface is alpha blended with 66% transparency" + }, + { + "name": "blend_100", + "description": "Surface is alpha blended using the texture's transparency" + }, + { + "name": "no_draw", + "description": "Surface is not drawn (caulk)" + }, + { + "name": "hint", + "description": "Surface is a primary BSP decision node" + }, + { + "name": "skip", + "description": "Surface is ignored completely (use on 'hint' brushes)" + }, + { + "name": "alpha_test", + "description": "Surface is alpha tested (foliage, fences, ..)" + }, + { + "name": "phong", + "description": "Surface is Phong shaded (smooth lighting)" + }, + { + "name": "material", + "description": "Surface is not drawn, but material stages are" + }, + { + "name": "decal", + "description": "Surface is an alpha blended decal (optimization)" + } + ], + "contentflags": [ + { + "name": "solid", + "description": "Brush is solid and opaque" + }, + { + "name": "window", + "description": "Brush is a solid and transparent" + }, + { "unused": true }, + { + "name": "lava", + "description": "Brush is lava" + }, + { + "name": "slime", + "description": "Brush is slime" + }, + { + "name": "water", + "description": "Brush is water" + }, + { + "name": "mist", + "description": "Brush is mist" + }, + { + "name": "atmospheric", + "description": "Brush is atmospheric" + }, + { "unused": true }, + { "unused": true }, + { "unused": true }, + { "unused": true }, + { "unused": true }, + { "unused": true }, + { "unused": true }, + { "unused": true }, + { + "name": "player_clip", + "description": "Brush will collide with players, but is not visible" + }, + { + "name": "monster_clip", + "description": "Brush will collide with monsters, but is not visible" + }, + { + "name": "current_0", + "description": "Brush has a current in direction of 0 degrees" + }, + { + "name": "current_90", + "description": "Brush has a current in direction of 90 degrees" + }, + { + "name": "current_180", + "description": "Brush has a current in direction of 180 degrees" + }, + { + "name": "current_270", + "description": "Brush has a current in direction of 270 degrees" + }, + { + "name": "current_up", + "description": "Brush has a current in the up direction" + }, + { + "name": "current_down", + "description": "Brush has a current in the down direction" + }, + { + "name": "origin", + "description": "Brush specifies origin of rotation for an inline model" + }, + { + "name": "monster", + "description": "Brush is meat that can die" + }, + { + "name": "dead_monster", + "description": "Brush is meat that can not die" + }, + { + "name": "detail", + "description": "Brush is a detail and should not split structural brushes" + }, + { "unused": true }, + { + "name": "ladder", + "description": "Brush is a ladder" + } + ] + }, + "softMapBounds": "-4096 -4096 -4096 4096 4096 4096" +} diff --git a/tools/trenchbroom/games/Quetoo/Icon.png b/tools/trenchbroom/games/Quetoo/Icon.png new file mode 100644 index 0000000..1ebb76c Binary files /dev/null and b/tools/trenchbroom/games/Quetoo/Icon.png differ diff --git a/tools/trenchbroom/games/Quetoo/Quetoo.fgd b/tools/trenchbroom/games/Quetoo/Quetoo.fgd new file mode 100644 index 0000000..d9ba485 --- /dev/null +++ b/tools/trenchbroom/games/Quetoo/Quetoo.fgd @@ -0,0 +1,553 @@ +// Quetoo Forge Game Data File (.fgd) + +@BaseClass = Phong [ + phong(integer) : "The Phong shading threshold for this model, in degrees" : 60 +] + +@BaseClass = Targetname [ + targetname(target_source) : "The target name of this entity if it is to be triggered" +] + +@BaseClass = Target [ + target(target_destination) : "The entity to target" +] + +@BaseClass size(-16 -16 -16, 16 16 16) = Item +[ + spawnflags(Flags) = + [ + 1 : "triggered" : 0 + 2 : "no_touch" : 0 + 4 : "hover" : 0 + ] + team(string) : "The team name for alternating item spawns" +] + +@PointClass base(Item) color(0 255 0) size(-4 -4 -6, 4 4 6) studio("") = item_armor_shard : "Shard armor (+3)" [] +@PointClass base(Item) color(255 0 0) studio("") = item_armor_body : "Body armor (+200)" [] +@PointClass base(Item) color(255 255 0) studio("") = item_armor_combat : "Combat armor (+100)" [] +@PointClass base(Item) color(0 255 0) studio("") = item_armor_jacket : "Jacket armor (+50)" [] + +@PointClass base(Item) color(40 255 40) size(-4 -4 -6, 4 4 6) studio("") = item_health_small : "Small health (+3)" [] +@PointClass base(Item) color(220 180 0) studio("") = item_health : "Health (+15)" [] +@PointClass base(Item) color(240 60 40) studio("") = item_health_large : "Large health (+25)" [] +@PointClass base(Item) color(30 100 200) studio("") = item_health_mega : "Megahealth (+75)" [] + +@PointClass base(Item) color(80 100 255) studio("") = item_adrenaline : "Adrenaline" [] +@PointClass base(Item) color(20 180 180) studio("") = item_quad : "Quad damage" [] + +@BaseClass base(Item) size(-8 -8 -24, 8 8 32) studio("") = TeamFlag [] +@PointClass base(TeamFlag) color(255 0 0) = item_flag_team1 : "Red flag" [] +@PointClass base(TeamFlag) color(0 0 255) = item_flag_team2 : "Blue flag" [] +@PointClass base(TeamFlag) color(255 255 0) = item_flag_team3 : "Yellow flag" [] +@PointClass base(TeamFlag) color(0 0 255) = item_flag_team4 : "Green flag" [] + +@BaseClass base(Item) size(-16 -6 -6, 16 6 6) = Weapon [] +@PointClass base(Weapon) color(225 200 40) studio("") = weapon_blaster : "Blaster" [] +@PointClass base(Weapon) color(220 160 0) studio("") = weapon_shotgun : "Shotgun" [] +@PointClass base(Weapon) color(220 160 0) studio("") = weapon_supershotgun : "Super shotgun" [] +@PointClass base(Weapon) color(255 255 0) studio("") = weapon_machinegun : "Machinegun" [] +@PointClass base(Weapon) color(0 160 0) studio("") = weapon_grenadelauncher : "Grenade launcher" [] +@PointClass base(Weapon) color(200 0 0) studio("") = weapon_rocketlauncher : "Rocket launcher" [] +@PointClass base(Weapon) color(100 200 255) studio("") = weapon_hyperblaster : "Hyperblaster" [] +@PointClass base(Weapon) color(225 225 225) studio("") = weapon_lightning : "Lightning" [] +@PointClass base(Weapon) color(0 0 200) studio("") = weapon_railgun : "Rail gun" [] +@PointClass base(Weapon) color(80 255 40) studio("") = weapon_bfg : "BFG10K" [] + +@BaseClass base(Item) size(-10 -8 -8, 10 8 8) = Ammo [] +@PointClass base(Ammo) color(220 160 0) studio("") = ammo_shells : "Shells for the Shotgun and Super Shotgun" [] +@PointClass base(Ammo) color(255 255 0) studio("") = ammo_bullets : "Bullets for the machinegun" [] +@PointClass base(Ammo) color(0 160 0) studio("") = ammo_grenades : "Grenades for the Grenade Launcher" [] +@PointClass base(Ammo) color(200 0 0) studio("") = ammo_rockets : "Rockets for the Rocket Launcher" [] +@PointClass base(Ammo) color(100 200 255) studio("") = ammo_cells : "Cells for the Hyperblaster" [] +@PointClass base(Ammo) color(225 225 225) studio("") = ammo_bolts : "Bolts for the Lightning" [] +@PointClass base(Ammo) color(0 0 200) studio("") = ammo_slugs : "Slugs for the Railgun" [] +@PointClass base(Ammo) color(80 255 40) studio("") = ammo_nukes : "Nukes for the BFG10K" [] + +@SolidClass base(Phong, Target, Targetname) color(0 255 255) = func_button : "When a button is touched by a player, it moves in the direction set by the 'angle' key, triggers all its targets, stays pressed by the amount of time set by the 'wait' key, then returns to its original position where it can be operated again." +[ + angle(integer) : "Determines the direction in which the button will move (up = -1, down = -2)" + target(target_destination) : "All entities with a matching target name will be triggered" + speed(integer) : "Speed of the button's displacement" : 40 + wait(integer) : "Number of seconds the button stays pressed (-1 = indefinitely)" : 1 + lip(integer) : "Lip remaining at end of move" : 4 + sounds(integer) : "The sound set for the button (-1 = silent)" : 0 + health(integer) : "If set, the button must be killed instead of touched to use" +] + +@SolidClass base(Phong, Targetname) color(0 255 255) = func_conveyor : "Conveyors are stationary brushes that move what's on them. The brush should be have a surface with at least one current content enabled." +[ + spawnflags(Flags) = + [ + 1 : "The conveyor will be active immediately" : 0 + 2 : "The conveyor is toggled each time it is used" : 0 + ] + speed(integer) : "The speed at which objects on the conveyor are moved" : 100 +] + +@SolidClass base(Phong, Targetname) color(0 255 255) = func_door : "A sliding door. By default, doors open when a player walks close to them." +[ + spawnflags(Flags) = + [ + 1 : "The door to moves to its destination when spawned, and operates in reverse" : 0 + 2 : "The door will wait in both the start and end states for a trigger event" : 0 + ] + message(string) : "An optional string printed when the door is first touched" + angle(integer) : "Determines the opening direction of the door (up = -1, down = -2)" + health(integer) : "If set, door must take damage to open" + speed(integer) : "The speed with which the door opens" : 100 + wait(integer) : "Wait before returning (-1 = never return)" : 3 + lip(integer) : "The lip remaining at end of move" : 8 + dmg(integer) : "The damage inflicted on players who block the door as it closes" : 2 + sounds(integer) : "The sound set for the door (0 metal, 1 stone, -1 silent)" : 0 +] + +@SolidClass base(Phong, Targetname) color(0 255 255) = func_door_rotating : "A door which rotates about an origin on its Z axis. By default, doors open when a player walks close to them." +[ + spawnflags(Flags) = + [ + 1 : "The door to moves to its destination when spawned, and operates in reverse" : 0 + 2 : "The door will wait in both the start and end states for a trigger event" : 0 + 4 : "The door will rotate in the opposite (negative) direction along its axis" : 0 + 8 : "The door will rotate along its X axis" : 0 + 16 : "The door will rotate along its Y axis" : 0 + ] + message(string) : "An optional string printed when the door is first touched" + health(integer) : "If set, door must take damage to open" + speed(integer) : "The speed with which the door opens" : 100 + rotation(integer) : "The rotation the door will open, in degrees": 90 + wait(integer) : "Wait before returning (-1 = never return)" : 3 + dmg(integer) : "The damage inflicted on players who block the door as it closes" : 2 + sounds(integer) : "The sound set for the door (0 metal, 1 stone, -1 silent)" : 0 +] + +@SolidClass base(Phong, Targetname) color(0 255 255) = func_door_secret : "A secret door which opens when shot, or when targeted. The door first slides back, and then to the side." +[ + spawnflags(Flags) = + [ + 1 : "The door will open when shot, even if it is targeted" : 0 + 2 : "The door will first slide to the left" : 0 + 4 : "The door will first slide down" : 0 + ] + angle(integer) : "The angle at which the door opens" + message(string) : "An optional string printed when the door is first touched" + health(integer) : "If set, door must take damage to open" + speed(integer) : "The speed with which the door opens" : 100 + wait(integer) : "Wait before returning (-1 = never return)" : 3 + dmg(integer) : "The damage inflicted on players who block the door as it closes" : 2 +] + +@SolidClass base(Phong) color(0 255 180) = func_group : "Groups brushes together in Trenchbroom for convenience. When the map is compiled, these entities are merged back into worldspawn." [] + +@SolidClass base(Phong, Targetname) color(0 255 255) = func_plat : "Rising platform the player can ride to reach higher places. Platforms must be placed in the raised position, so they will operate and be lit correctly, but they spawn in the lowered position. If the platform is the target of a trigger or button, it will start out disabled and in the extended position." +[ + spawnflags(Flags) = + [ + 1 : "The touch field for this platform will only exist at the lower position" : 0 + ] + speed(integer) : "The speed with which the platform moves" : 200 + accel(integer) : "The platform acceleration" : 500 + lip(integer) : "The lip remaining at end of move" : 8 + height(integer) : "If set, this will determine the extent of the platform's movement, rather than implicitly using the platform's height" + sounds(integer) : "The sound set for the platform (0 metal, 1 stone, -1 silent)" +] + +@SolidClass base(Targetname) color(0 255 255) = func_rotating : "Solid entity that rotates continuously. Rotates on the Z axis by default and requires an origin brush. It will always start on in the game and is not targetable." +[ + spawnflags(Flags) = + [ + 1 : "The entity will spawn rotating" : 0 + 2 : "Will cause the entity to rotate in the opposite direction" : 0 + 4 : "The entity will rotate on the X axis" : 0 + 8 : "The entity will rotate on the Y axis" : 0 + 16 : "The entity will inflict damage when touced" : 0 + 32 : "IThe entity will stop rotating when blocked" : 0 + ] + speed(integer) : "The speed at which the entity rotates" : 100 + dmg(integer) : "The damage to inflict to players who touch or block the entity" : 2 +] + +@PointClass base(Target, Targetname) color(0 255 255) size(-8 -8 -8, 8 8 8) = func_timer : "Time delay trigger that will continuously fire its targets after a preset time delay. The time delay can also be randomized. When triggered, the timer will toggle on/off." +[ + spawnflags(Flags) = + [ + 1 : "The timer will begin firing once spawned" : 0 + ] + wait(integer) : "Delay in seconds between each triggering of all targets" : 1 + random(integer) : "Random time variance in seconds added to 'wait' delay (default 0.5 * wait)" + delay(integer) : "Additional delay before the first firing when start_on" : 0 +] + +@SolidClass base(Phong, Targetname) color(0 255 255) = func_train : "Trains are moving solids that players can ride along a series of path_corners. The origin of each corner specifies the lower bounding point of the train at that corner. If the train is the target of a button or trigger, it will not begin moving until activated." +[ + spawnflags(Flags) = + [ + 1 : "The train will begin moving once spawned" : 0 + 2 : "The train will start or stop each time it is activated" : 0 + 4 : "The train will stop when blocked, and inflict no damage" : 0 + ] + dmg(integer) : "The damage inflicted on players who block the train" : 2 + speed(integer) : "The speed with which the train moves" : 100 + sound(string) : "The looping sound to play while the train is in motion" +] + +@SolidClass base(Phong, Targetname) color(0 255 255) = func_wall : "A solid that may spawn into existence via trigger." +[ + spawnflags(Flags) = + [ + 1 : "The wall is inhibited until triggered, at which point it appears and kills everything in its way" : 0 + 2 : "The wall may be triggered off and on" : 0 + 4 : "The wall will initially be present, but can be toggled off" : 0 + ] +] + +@SolidClass base(Phong, Targetname) color(0 255 255) = func_water : "A movable water brush, which must be targeted to operate." +[ + spawnflags(Flags) = + [ + 1 : "The water will move to its destination when spawned and operate in reverse" : 0 + ] + angle(integer) : "Determines the opening direction (up = -1, down = -2)" + speed(integer) : "The speed at which the water moves" : 25 + wait(integer) : "Delay in seconds before returning to the initial position" : -1 + lip(integer) : "Lip remaining at end of move" : 0 +] + +@PointClass base(Targetname) color(0 180 0) size(-4 -4 -4, 4 4 4) = info_null : "A positional target for spotlights, etc. These are inhibited in the game and are only useful to the editor and BSP compiler." [] +@PointClass base(Targetname) color(0 180 180) size(-4 -4 -4, 4 4 4) = info_notnull : "A positional target for other entities. Unlike info_null, these are available in the game and can be targeted by other entities (e.g. info_player_intermission)."[] + +@BaseClass size(-16 -16 -24, 16 16 32) = Spawn [ + angle(integer) : "The angle at which the player will face when spawned" +] +@PointClass base(Spawn) color(255 255 255) = info_player_start : "Single player spawn point." [] +@PointClass base(Spawn) color(255 0 255) = info_player_deathmatch : "Deathmatch spawn point." [] +@PointClass base(Spawn) color(255 0 0) = info_player_team1 : "Player spawn point for red team in teams or CTF gameplay." [] +@PointClass base(Spawn) color(0 0 255) = info_player_team2 : "Player spawn point for blue team in teams or CTF gameplay." [] +@PointClass base(Spawn) color(255 255 0) = info_player_team3 : "Player spawn point for yellow team in teams or CTF gameplay." [] +@PointClass base(Spawn) color(0 255 0) = info_player_team4 : "Player spawn point for green team in teams or CTF gameplay." [] +@PointClass base(Spawn, Target) color(0 255 255) = info_player_intermission : "Camera for intermission screen between matches." +[ + angles(string) : "The pitch yaw roll angles for the camera (e.g. 20 270 0)." +] + +@PointClass base(Target) color(255 255 255) size(-6 -6 -6, 6 6 6) = light : "Point light source." +[ + light(integer) : "Light radius" : 300 + _color(string) : "Light color as 3 decimal values from 0.0 - 1.0" : "1 1 1" + _intensity(float) : "Light intensity as a positive scalar value" : "1" + _size(integer) : "Light size, to simulate area lights and cast penumbrae" : 16 +] + +@PointClass base(Target) color(200 255 255) size(-6 -6 -6, 6 6 6) = light_spot : "Point light source with attenuation cone." +[ + angle(integer) : "Spotlight direction (up = -1, down = -2, yaw = positive value)" + light(integer) : "Spotlight radius" : 300 + _color(string) : "Spotlight color as 3 decimal values from 0.0 - 1.0" : "1 1 1" + _cone(integer) : "Spotlight attenuation cone width, in degrees" : 22 + _intensity(float) : "Spotlight intensity as a positive scalar value" : "1" + _size(integer) : "Spotlight size, to simulate area lights and cast penumbrae" : 16 +] + +@PointClass base(Target) color(255 255 0) size(-16 -16 -16, 16 16 16) = light_sun : "Directional sun light source." +[ + _color(string) : "Sun color as 3 decimal values from 0.0 - 1.0" : "1 1 1" + _intensity(float) : "Sun intensity as a positive scalar value" : "1" + _size(integer) : "Sun size, to simulate area lights and cast penumbrae" : 256 +] + +@SolidClass color(180 180 150) = misc_dust : "Dust volumes emit configurable sprites, like localized weather. These are useful for creating dust, bubbles, foam, mist, etc. These are typically contents atmospheric." +[ + acceleration(string) : "The sprite acceleration" : "0 0 0" + _color(string) : "The sprite HSVA color as 4 decimal values" : "0 0 1 1" + dir(string) : "The sprite directional axis (0 0 0 is billboard)" : "0 0 0" + density(float) : "The sprite density" : "1" + _end_color(string) : "The sprite HSVA end color as 4 decimal values" : "0 0 0 0" + height(float) : "The sprite height. Setting this will cause size to be ignored" : "0" + lifetime(float) : "The sprite lifetime in seconds" : "10" + lighting(float) : "The sprite lighting scalar" : "1" + rotation(float) : "The sprite rotation in degrees" : "0" + rotation_velocity(float) : "The sprite rotation velocity in degrees per second" : "0" + _size(float) : "The sprite size" : "1" + size_velocity(float) : "The sprite size velocity" : "0" + size_acceleration(float) : "The sprite size acceleration" : "0" + softness(float) : "The sprite softness scalar" : "1" + sprite(string) : "The sprite image name" : "particle1" + velocity(string) : "The sprite velocity" : "0 0 0" + width(float): "The sprite width. Setting this will cause size to be ignored" : "0" +] + +@PointClass color(255 80 20) size(-6 -6 -6, 6 6 6) = misc_fireball : "Spawns an intermittent fireball that damages players. These are typically used above lava traps for ambiance." +[ + angles(string) : "The angles at which the fireball will fly" + dmg(integer) : "The damage inflicted to entities that touch the fireball" : 4 + random(float) : "Random time variance in seconds added to wait delay" + speed(float) : "The speed at which the fireball will fly" : "600" + wait(float) : "The interval in seconds between fireball emissions" : "5" +] + +@PointClass color(255 120 20) size(-16 -16 -16, 16 16 16) = misc_flame : "Client-side flame emitter, useful for torches and ambience." +[ + density(float) : "The flame density" : "1" + drift(float) : "The factor of randomized drift applied to the emission rate" + hz(float) : "The emission rate, in events-per-second" : "10" + radius(float) : "The flame radius" : "16" + sound(string) : "The looping sound to play, or 'none' to disable" : "world/fire" +] + +@SolidClass color(230 230 230) = misc_fog : "Fog volumes. When compiled, fog brushes are merged into the world. Fog volumes are processed during the lighting compile phase. These are typically contents atmospheric, but can be contents water, etc. Omit _color to use the material color." +[ + _color(string) : "The sprite HSVA color as 4 decimal values" : "0 0 1 1" + absorption(float) : "The fog absorption, or how much light color it absorbs" : ".5" + density(float) : "The fog density, or thickness" : "1" + noise(float) : "The fog noise, or variation in density" : "0" + frequency(float) : "The simplex noise frequency - effectively the scale of the noise texture" : "32" + amplitude(float) : "The simplex noise amplitude - effectively the upper limit of noise values" : "1" + lacunarity(float) : "The simplex noise lacunarity - multiplier per-octave of frequency" : "2" + persistence(float) : "The simplex noise persistence - multiplier per-octave of amplitude" : "0.5" + octaves(float) : "The number of octaves to sample" : "5" + seed(float) : "The simplex noise permutation vector seed" : "0" + offset(string) : "An offset added to the noise calculation" : "0 0 0" +] + +@PointClass color(80 180 80) size(-16 -16 -16, 16 16 16) = misc_model : "Client-side emission of static models (non-interactive map objects). These are useful for placing trees, torches, and other non-brush scenery." +[ + angles(string) : "The angles of orientation for the model" + scale(float) : "The scale for a static model" + model(string) : "The static model name, e.g. trees/mytree" +] + +@PointClass color(40 120 40) size(-8 -8 -8, 8 8 8) = misc_sound : "Client-side emission of ambient sounds." +[ + atten(choices) : "The attenuation" : 2 = + [ + 0 : "None" + 1 : "Linear" + 2 : "Exponential" + 3 : "Cubic" + ] + drift(float) : "The factor of randomized drift applied to the emission rate" + hz(float) : "The emission rate, in events-per-second" : "0" + sound(string) : "The sound name, e.g. edge/wind" +] + +@PointClass base(Target) color(220 200 20) size(-4 -4 -4, 4 4 4) = misc_sparks : "Client-side emission of spark effects." +[ + angle(integer) : "Sparks direction (up = -1, down = -2, yaw = positive value)" + drift(float) : "The factor of randomized drift applied to the emission rate" + hz(float) : "The emission rate, in events-per-second" : "0" + target(target_source) : "The name of the entity to target to resolve the sparks direction." +] + +@PointClass color(120 120 200) size(-24 -24 -24, 24 24 24) = misc_sprite : "Highly configurable client-side emission of sprites. These are useful for light volumes, blood dripping from walls, or anything else you can think of. If two instances of this entity are teamed, the game will emit randomized instances that mix the properties of both teammates." +[ + acceleration(string) : "The sprite acceleration" : "0 0 0" + _color(string) : "The sprite HSVA color as 4 decimal values" : "0 0 1 1" + count(integer) : "The count of sprites to emit per emission" : 1 + dir(string) : "The sprite directional axis (0 0 0 is billboard)" : "0 0 0" + density(float) : "The sprite density" : "1" + drift(float) : "The factor of randomized drift applied to the emission rate" + _end_color(string) : "The sprite HSVA end color as 4 decimal values" : "0 0 0 0" + height(float) : "The sprite height. Setting this will cause size to be ignored" : "0" + lifetime(float) : "The sprite lifetime in seconds" : "10" + lighting(float) : "The sprite lighting scalar" : "1" + rotation(float) : "The sprite rotation in degrees" : "0" + rotation_velocity(float) : "The sprite rotation velocity in degrees per second" : "0" + _size(float) : "The sprite size" : "1" + size_velocity(float) : "The sprite size velocity" : "0" + size_acceleration(float) : "The sprite size acceleration" : "0" + softness(float) : "The sprite softness scalar" : "1" + sprite(string) : "The sprite image name" : "particle1" + team(string) : "The team name, for emitting randomized sprites that mix properties" + velocity(string) : "The sprite velocity" : "0 0 0" + width(float): "The sprite width. Setting this will cause size to be ignored" : "0" +] + +@PointClass base(Target) color(220 220 220) size(-10 -10 -10, 10 10 10) = misc_steam : "Client-side emission of steam effects." +[ + count(integer) : "The count of sprites to emit per emission" : 1 + density(float) : "The flame density" : "1" + drift(float) : "The factor of randomized drift applied to the emission rate" + hz(float) : "The emission rate, in events-per-second" : "10" + radius(float) : "The flame radius" : "16" + size(float) : "The initial sprite size" : "32" + sound(string): "The looping sound to play, or 'none' to disable" : "world/steam" + target(target_source) : "The name of the entity to target to resolve the steam direction and velocity" + velocity(string) : "The steam velocity (if not specified via target)" : "0 0 32" +] + +@PointClass base(Target) color(0 255 0) size(-32 -32 -24, 32 32 -16) = misc_teleporter : "Warps players who touch this entity to the targeted misc_teleporter_dest entity." +[ + spawnflags(Flags) = + [ + 1 : "Suppress the default teleporter particle effects" : 0 + ] +] + +@PointClass base(Targetname) color(255 0 0) size(-32 -32 -24, 32 32 -16) = misc_teleporter_dest : "Teleport destination for misc_teleporters." +[ + angle(integer) : "Direction in which player will look when teleported" +] + +@PointClass base(Target, Targetname) color(128 76 0) size(-8 -8 -8, 8 8 8) = path_corner : "Path corner for func_trains." +[ + spawnflags(Flags) = + [ + 1 : "The path corner teleports the train as soon as it is selected" : 0 + 2 : "Suppress the default teleport effects" + ] + target(string) : "The next corner in the path" + pathtarget(string) : "An entity to be used by this path corner when targeted" +] + +@PointClass base(Targetname) color(255 255 80) size(-6 -6 -6, 6 6 6) = target_light : "Emits a user-defined light when used. Lights can be chained with teams. Use this entity to add switched lights. Use the wait key to synchronize color cycles with other entities." +[ + spawnflags(Flags) = + [ + 1 : "The light will start on" : 0 + ] + _color(string) : "The light color" : "1 1 1" + light(float) : "The light radius in units" : "300" + delay(float) : "The delay before activating, in seconds" : "0" + team(string) : "The team name for alternating lights" + wait(float) : "If specified, an additional cycle will fire after this interval" : "0" +] + +@PointClass base(Targetname) color(40 120 40) size(-8 -8 -8, 8 8 8) = target_speaker : "Plays a sound each time it is used, or in loop if requested. Use this entity only when a sound must be triggered by another entity. For ambient sounds, use the client-side version, misc_sound." +[ + spawnflags(Flags) = + [ + 1 : "The sound can be toggled, and will play in loop until used" : 0 + 2 : "The sound can be toggled, and will begin playing when used" : 0 + ] + atten(choices) : "The attenuation" : 1 = + [ + 0 : "None" + 1 : "Linear" + 2 : "Exponential" + 3 : "Cubic" + ] + sound(string) : "The sound name, e.g. voices/haunting" +] + +@PointClass base(Targetname) color(128 128 160) size(-8 -8 -8, 8 8 8) = target_string : "Displays a center-printed message to the player when used." +[ + message(string) : "The message to display" +] + +@SolidClass base(trigger_once) = trigger_multiple : "Triggers multiple targets at fixed intervals." +[ + wait(float) : "Interval in seconds between activations": "0.2" +] + +@SolidClass base(Target, Targetname) = trigger_once : "Triggers multiple targets once." +[ + spawnflags(Flags) = + [ + 1 : "The trigger must be targeted before it will activate" : 0 + 2 : "The trigger will fire when shot" : 0 + ] + delay(integer) : "Delay in seconds between activation and firing of targets" : 0 + message(string) : "An optional string to display when activated" + killtarget(string) : "The name of the entity or team to kill on activation" +] + +@PointClass base(Target, Targetname) color(128 128 128) = trigger_relay : "A trigger that can not be touched, but must be triggered by another entity." +[ + delay(integer) : "Delay in seconds between activation and firing of targets" : 0 + message(string) : "An optional string to display when activated" + killtarget(string) : "The name of the entity or team to kill on activation" +] + +@PointClass base(Target) color(128 128 128) = trigger_always : "Triggers targets once at level spawn." +[ + killtarget(string) : "Kill Target" + delay(integer) : "Time before triggering" +] + +@SolidClass base(Phong, Targetname) color(128 128 128) = trigger_hurt : "A trigger that inflicts damage when touched." +[ + spawnflags(Flags) = + [ + 1 : "The trigger must be activated before it will hurt players" : 0 + 2 : "The trigger is toggled each time it is activated" : 0 + 8 : "Armor will not absorb damage inflicted by this trigger" : 0 + 16 : "Decrease the damage rate to once per second" : 0 + ] + dmg(integer) : "The damage this trigger inflicts per activation" : 2 +] + +@PointClass base(Target) color(128 128 128) = trigger_exec : "Executes a console command or script file when activated." +[ + command(string) : "The console command(s) to execute." + script(string) : "The script file (.cfg) to execute." + delay(integer) : "The delay in seconds between activation and execution of the commands." +] + +@SolidClass base(Phong) color(180 120 64) = trigger_push : "Pushes the player in any direction. These are commonly used to make jump pads to send the player upwards. Using the angles key, you can project the player in any direction using 'pitch yaw roll.'" +[ + spawnflags(Flags) = + [ + 1 : "The pusher is freed after it is used once" : 0 + 2 : "The pusher emits sprite effects to indicate its location" : 0 + ] + angles(string) : "The direction to push the player in" : "0 0 0" + sound(string) : "The sound effect to play when the player is pushed" : "world/jumppad" + speed(integer) : "The speed with which to push the player" : 100 +] + +@SolidClass base(Phong, Target) color(200 200 40) = trigger_teleporter : "Touching this will warp players to the targeted misc_teleporter_dest entity. This is the brush form of misc_teleporter." [] + +@SolidClass base(Phong) = worldspawn : "The worldspawn entity defines global conditions and behavior for the entire level. All brushes not belonging to an explicit entity implicitly belong to worldspawn." +[ + message(string) : "The map title" + sky(string) : "The sky environment map" : "unit1_" + ambient(string) : "The ambient light level" : "0 0 0" + weather(choices) : "Weather effects" : "none" = + [ + "none" : "None" + "rain" : "Rain" + "snow" : "Snow" + ] + fog_color(string) : "Global fog color, as 3 decimal values from 0.0 - 1.0" : "0 0 0" + fog_density(float) : "Global fog density, a single positive scalar value" : "0" + gravity(integer) : "Gravity" : 800 + gameplay(choices) : "Weather effects" : "deathmatch" = + [ + "deathmatch" : "Deathmatch" + "instagib" : "Instagib" + "arena" : "Rocket Arena" + ] + hook(choices) : "Enables the grappling hook" : 0 = + [ + 0 : "Disabled" + 1 : "Enabled" + ] + teams(choices) : "Enables teams play" : 0 = + [ + 0 : "Disabled" + 1 : "Enabled" + 2 : "Auto-balanced" + ] + num_teams(choices) : "Specifies the number of teams for teams and CTF play" : 0 = + [ + 0 : "Disabled" + 2 : "2" + 3 : "3" + 4 : "4" + ] + ctf(choices) : "Enables CTF play" : 0 = [ + 0 : "Disabled" + 1 : "Enabled" + 2 : "Auto-balanced" + ] + match(choices) : "Enables match play (round-based elimination with warmup)" : 0 = + [ + 0 : "Disabled" + 1 : "Enabled" + ] + fraglimit(integer) : "The frag limit" : 20 + roundlimit(integer) : "The round limit" : 20 + capturelimit(integer) : "The capture limit" : 8 + timelimit(integer) : "The time limit in minutes" : 20 + give(string) : "A comma-delimited item string to give each player on spawn" +] diff --git a/tools/trenchbroom/games/Wrath/GameConfig.cfg b/tools/trenchbroom/games/Wrath/GameConfig.cfg new file mode 100644 index 0000000..177ec0f --- /dev/null +++ b/tools/trenchbroom/games/Wrath/GameConfig.cfg @@ -0,0 +1,134 @@ +{ + "version": 9, + "name": "Wrath", + "icon": "Icon.png", + "experimental": true, + "fileformats": [ +// brush primitives not yet implemented +// { "format": "Quake3" }, + { "format": "Quake3 (Valve)" }, + { "format": "Quake3 (legacy)" } + ], + "filesystem": { + "searchpath": "kp1", + "packageformat": { "extension": ".pk3", "format": "zip" } + }, + "materials": { + "root": "textures", + "extensions": [ ".tga", ".png", ".jpg", ".jpeg" ], + "shaderSearchPath": "scripts", // this will likely change when we get a material system + "excludes": [ "*sky_bk", "*sky_dn", "*sky_ft", "*sky_lf", "*sky_rt", "*sky_up", "*_bump", "*_gloss", "*_glow", "_luma", "*_norm" ] + }, + "entities": { + "definitions": [ "wrath.fgd" ], + "defaultcolor": "0.6 0.6 0.6 1.0" + }, + "tags": { + "brush": [ + { + "name": "Trigger", + "attribs": [ "transparent" ], + "match": "classname", + "pattern": "trigger_*", + "material": "common/trigger" + } + ], + "brushface": [ + { + "name": "Areaportal", + "attribs": [ "transparent" ], + "match": "surfaceparm", + "pattern": [ "areaportal" ] + }, + { + "name": "Caulk", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "common/*caulk" + }, + { + "name": "Clip", + "attribs": [ "transparent" ], + "match": "surfaceparm", + "pattern": [ "playerclip", "monsterclip" ] + }, + { + "name": "Clusterportal", + "attribs": [ "transparent" ], + "match": "surfaceparm", + "pattern": [ "clusterportal" ] + }, + { + "name": "Detail", + "match": "contentflag", + "flags": [ "detail" ] + }, + { + "name": "Hint", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "common/hint*" + }, + { + "name": "Liquid", + "match": "surfaceparm", + "pattern": [ "water", "lava", "slime" ] + }, + { + "name": "Skip", + "attribs": [ "transparent" ], + "match": "material", + "pattern": "common/*skip" + }, + { + "name": "Translucent", + "attribs": [ "transparent" ], + "match": "surfaceparm", + "pattern": [ "trans", "fog" ] + } + ] + }, + "faceattribs": { + "defaults": { + "scale": [1.0, 1.0] + }, + "surfaceflags": [], + "contentflags": [ + { "unused": true }, // 1 + { "unused": true }, // 2 + { "unused": true }, // 4 + { "unused": true }, // 8 + { "unused": true }, // 16 + { "unused": true }, // 32 + { "unused": true }, // 64 + { "unused": true }, // 128 + { "unused": true }, // 256 + { "unused": true }, // 512 + { "unused": true }, // 1024 + { "unused": true }, // 2048 + { "unused": true }, // 4096 + { "unused": true }, // 8192 + { "unused": true }, // 16384 + { "unused": true }, // 32768 + { "unused": true }, // 65536 + { "unused": true }, // 131,072 + { "unused": true }, // 262,144 + { "unused": true }, // 524,288 + { "unused": true }, // 1,048,576 + { "unused": true }, // 2,097,152 + { "unused": true }, // 4,194,304 + { "unused": true }, // 8,388,608 + { "unused": true }, // 16,777,216 + { "unused": true }, // 33,554,432 + { "unused": true }, // 67,108,864 + { + "name": "detail", + "description": "Detail brush" + } // 134,217,728 + ] + }, + "softMapBounds":"-65536 -65536 -65536 65536 65536 65536", + "compilationTools": [ + { "name": "q3map2", "description": "Path to your q3map2 executable, which performs the main bsp/vis/light compilation phases" } + ] +} diff --git a/tools/trenchbroom/games/Wrath/Icon.png b/tools/trenchbroom/games/Wrath/Icon.png new file mode 100644 index 0000000..a16fd90 Binary files /dev/null and b/tools/trenchbroom/games/Wrath/Icon.png differ diff --git a/tools/trenchbroom/games/Wrath/wrath.fgd b/tools/trenchbroom/games/Wrath/wrath.fgd new file mode 100644 index 0000000..4a7bbd3 --- /dev/null +++ b/tools/trenchbroom/games/Wrath/wrath.fgd @@ -0,0 +1,386 @@ +// UNOFFICIAL WRATH FGD +// Name : wrath.fgd +// Version : 202009160800 +// Edited by: xaGe + +// This is very basic but includes all weapons, pickups, and enemies. I am sure the Wrath team has a very awesome game definition +// file they use to make the game that will be released after the game is finalized. Until then I will try to add any new entities +// introduced to the game until then. + + +@SolidClass = worldspawn : "World entity" +[ + _lightmapscale(integer) : "Description" : 1 + fog(string) : "Description" : "" + gridsize(string) : "Description" : "" + sounds(integer) : "Description" : 2 + _blocksize(integer) : "Description" : 2048 + message(string) : "Message to player" : "Map name" +] + +@PointClass size(-16 -16 -24, 16 16 32) color(0 255 0) = info_player_start : "Player start position" +[ + location(integer) : "Description" : 1 + health(integer) : "Starting health" : 75 + nomelee(integer) : "Description" : 0 +] + +@SolidClass = func_water : "Description" +[ + watertype(integer) : "Water type" : -3 + cshift(string) : "unknown" : "8 32 16 128" + colormod(string) : "RED GREEN BLUE" : ".5 .55 .5" + alpha(string) : "water transparency" : "0.75" + _lightmapscale(integer) : "Description" : 2 + deep(integer) : "Description" : 1 +] + +@PointClass model({ "path" : model}) = place_model : "misc model entity" +[ + model(string) : "subdir path/to/model.md3" : "models/portals/portal_generic.md3" +] + + + +@SolidClass = func_particles : "Description" +[ + density(integer) : "Description" : 20 + delay(string) : "Description" : "0.1" + particlename(string) : "Description" : "waterfall_base1" +] + +@PointClass = soundbox : "sound entity" +[ + rad_sound(integer) : "unknown" : 2048 + volume(integer) : "volume level" : 1 + noise(string) : "sound to play" : "sound/doors/e1m2_pillar.ogg" + targetname(string) : "name" : "FWTBT" +] + +@PointClass size(-16 -16 -0, 16 16 48) model({"path": "models/objects/fixtures/fire1.md3", "skin": 0}) = object_fire1 : "fire" +[ + _tb_group(integer) : "Description" : 118 +] + +@PointClass size(-8 -8 -8, 8 8 8) color(180 220 228) = light : "Non-displayed light. Lights pointed at a target will be spotlights." +[ + light(integer) : "Brightness" : 300 + _color(color1) : "RGB Color" : "1 1 0.5" + spawnflags(flags) = + [ + 1 : "Linear" : 0 : "Gives light linear falloff instead of inverse square." + ] +] +@SolidClass = func_destruct : "brush entity then can be destroyed by player" +[ + spawnflags(integer) : "Description" : 1 + targetname(string) : "name" : "destructo_discs2" + particlename(string) : "particle type to display" : "stone1" + gibmodel3(string) : "md3 model chunks to throw" : "models/destruct/e1m2/stone1_c.md3" + gibmodel2(string) : "md3 model chunks to throw" : "models/destruct/e1m2/stone1_b.md3" + gibmodel1(string) : "md3 model chunks to throw" : "models/destruct/e1m2/stone1_a.md3" + base_scale(string) : "Description" : "1.5" + type(integer) : "Description" : 0 + noise(string) : "Noise to make when broke" : "sound/impact/destruct/stone_break1.ogg" + health(integer) : "Description" : 10 + gibcount(integer) : "Description" : 35 + mass(string) : "Description" : "0.75" + rad_sound(integer) : "Description" : 1024 + volume(integer) : "Description" : 1 + bouncefactor(string) : "Description" : "0.25" + spread_vel(integer) : "Description" : 200 + only_damage_monster(integer) : "Description" : 1 + target(string) : "Target" : "Bresil" + _phong(integer) : "Description" : 1 +] + +@PointClass size(-32 -32 -0, 32 32 48) model({"path": "models/objects/coffers/coffer1_locked.md3"}) = object_coffer : "object_coffer" +[ + coffer_health(integer) : "Description" : 2 + coffer_armor(integer) : "Description" : 2 + coffer_ammo(integer) : "Description" : 4 + coffer_artifacts(integer) : "Description" : 5 + keyrequired(integer) : "Description" : 1 +] + +@PointClass size(-8 -8 -8, 8 8 8) model({"path": "models/items/lifeblood_beaker.md3"}) = health_life_beaker : "health beaker" [] +@PointClass size(-8 -8 -8, 8 8 8) model({"path": "models/items/lifeblood_vial.md3"}) = health_life_vial : "health vial" [] +@PointClass size(-16 -16 -48, 16 16 8) model({"path": "models/items/coffer_key1.md3"}) = key_coffer : "key_coffer" [] +@PointClass size(-8 -8 -8, 8 8 8) model({"path": "models/items/armor_shard.md3"}) = armor_shard : "Description" [] +@PointClass size(-8 -8 -8, 8 8 8) model({"path": "models/items/armor_shard_dark.md3"}) = armor_shard_dark : "dark armor shard" [] +@PointClass = portal_hub1 : "point entity" [] + + +@PointClass size(-16 -16 -10, 16 16 22) model({"path": "models/items/armor.md3"}) = armor_armor : "chest armor" [] +@PointClass size(-16 -16 -16, 16 16 16) model({"path": "models/items/helm.md3"}) = armor_helm : "Description" [] +@PointClass size(-16 -16 -32, 16 16 16) model({"path": "models/artifacts/cruel_aegis.md3"}) = artifact_cruel_aegis : "Artifact: Cruel Aegis" [] +@PointClass size(-16 -16 -32, 16 16 16) model({"path": "models/artifacts/drowners_apparatus.md3"}) = artifact_drowners_apparatus : "Artifact: Drowners Apparatus" [] +@PointClass size(-16 -16 -32, 16 16 16) model({"path": "models/artifacts/soul_tether.md3"}) = artifact_soul_tether : "Artifact: Soul Tether" [] +@PointClass size(-16 -16 -32, 16 16 16) model({"path": "models/artifacts/life_siphon.md3"}) = artifact_life_siphon : "Artifact: Life Siphon" +[ + secret(integer) : "Description" : 1 + targetname(string) : "Description" : "Bresil" +] + +@PointClass size(-16 -16 -0, 16 16 32) model({"path": "models/destruct/urns/urn32.md3"}) = breakable_urn_small : "small urn" +[ + urn_health(integer) : "Description" : 2 + urn_armor(integer) : "Description" : 2 + urn_ammo(integer) : "Description" : 4 + health(integer) : "Description" : 1 +] + +@PointClass size(-16 -16 -0, 16 16 48) model({"path": "models/destruct/urns/urn48.md3"}) = breakable_urn_medium : "medium urn" +[ + urn_health(integer) : "Description" : 1 + urn_ammo(integer) : "Description" : 4 + urn_armor(integer) : "Description" : 2 + health(integer) : "Description" : 1 +] + +@PointClass size(-16 -16 -0, 16 16 64) model({"path": "models/destruct/urns/urn64.md3"}) = breakable_urn_large : "large urn" +[ + urn_armor(integer) : "Description" : 2 + urn_ammo(integer) : "Description" : 3 + urn_artifacts(integer) : "Description" : 5 + urn_health(integer) : "Description" : 1 + health(integer) : "Description" : 1 +] + +@PointClass size(-16 -16 -16, 16 16 16) model({"path": "models/items/helm_dark.md3"}) = armor_helm_dark : "dark helmet" [] + +@PointClass = enemy_spawner : "Description" +[ + classmonster2(integer) : "Description" : 1 + spawnflags(integer) : "Description" : 1 + classmonster1(integer) : "Description" : 1 + targetname(string) : "Description" : "OhYes" + type(integer) : "Description" : 0 + turret(integer) : "Description" : 1 + rise(integer) : "Description" : 1 + target(string) : "Description" : "GaucheDroite" + likecharge(integer) : "Description" : 1 + angles(string) : "Description" : "0.128108 45.0278 1.56751" + classmonster4(integer) : "Description" : 1 + classmonster3(integer) : "Description" : 1 + delay(integer) : "Description" : 5 + count(integer) : "Description" : 1 + wait(string) : "Description" : ".2" + classmonster5(integer) : "Description" : 11 +] + +@PointClass size(-16 -16 -16, 16 16 16) model({"path": "models/objects/switches/e1_switch1.md3"}) = switch_e1_switch1 : "A switch" +[ + target(string) : "Description" : "IMustGoOn" + wait(integer) : "Description" : -1 + delay(string) : "Description" : ".2" +] + +@PointClass = enemy_spawner_warp : "enemy spawner that warps in monsters" +[ + turret(integer) : "Description" : 1 + targetname(string) : "Description" : "OnEnAGros1" + spawnflags(integer) : "Description" : 1 + fastwarp(integer) : "Description" : 1 + target(string) : "Description" : "HEY3" + likecharge(integer) : "Description" : 1 + type(integer) : "Description" : 1 + wait(string) : "Description" : "1.5" + delay(integer) : "Description" : 2 + count(integer) : "Description" : 1 + classmonster1(integer) : "Description" : 2 + classmonster2(integer) : "Description" : 11 + classmonster3(integer) : "Description" : 11 + classmonster4(integer) : "Description" : 11 + classmonster5(integer) : "Description" : 11 +] + +@PointClass = path_corner : "Path corner entity that func_trains can be made to follow." +[ + wait(integer) : "Description" : -1 + target(string) : "Description" : "Posthuman1" + targetname(string) : "Description" : "Posthuman" + speed(integer) : "Description" : 224 +] + +@PointClass = item_spawner : "Spawns items" +[ + targetname(string) : "Description" : "BigTiddiesFTW" + classitem2(integer) : "Description" : 9 + classitem1(integer) : "Description" : 9 + classitem5(integer) : "Description" : 9 + classitem4(integer) : "Description" : 9 + classitem3(integer) : "Description" : 9 + spawnflags(integer) : "Description" : 1024 +] + +@PointClass size(-16 -16 -48, 16 16 16) model({"path": "models/items/glyph_red.md3"}) = key_red : "red key" +[ + target(string) : "Description" : "RedKey1" +] + +@PointClass size(-16 -16 -48, 16 16 16) model({"path": "models/items/relic.md3"}) = relic_e1m1 : "Description" +[ + target(string) : "Description" : "portal_level_to_hub1" +] + +@PointClass = teleporter : "Description" +[ + inactive(integer) : "Description" : 1 + target(string) : "Description" : "ToHere1" + targetname(string) : "Description" : "ToHere2" +] + +@PointClass size(-8 -8 -24, 8 8 16) model({"path": "models/objects/fixtures/torch1.md3"}) = object_torch1 : "flamey wall torch" +[ + skin(integer) : "Description" : 1 + _tb_group(integer) : "Description" : 114 +] + +@PointClass size(-16 -16 -10, 16 16 22) model({"path": "models/items/armor_dark.md3"}) = armor_armor_dark : "chest armor dark" [] +@PointClass size(-64 -64 -64, 64 64 64) model({"path": "models/portals/portal_generic.md3"}) = portal_level_to_hub : "Portal to hub" +[ + location(integer) : "Description" : 2 + targetname(string) : "Description" : "portal_level_to_hub" + model(string) : "Description" : "models/portals/portal_level_to_hub.md3" + map(string) : "Description" : "hub1" +] + +@PointClass = info_null : "point entity Used as a positional target for light entities to create a spotlight effect." +[ + targetname(string) : "Description" : "I can make magic" +] + +@PointClass size(-16 -16 -48, 16 16 16) model({"path": "models/items/relic.md3"}) = relic_e1m2 : "Relic: E1M2" +[ + target(string) : "Description" : "portal_level_to_hub" +] + +// Spawners + +// Monster_* +@PointClass size(-16 -16 -32, 16 16 40) model({"path": "models/enemies/afflicted/afflicted.md3"}) = monster_afflicted : "Monster: Afflicted" [] +@PointClass size(-40 -40 -32, 40 40 64) model({"path": "models/enemies/executioner/executioner.md3"}) = monster_executioner : "Monster: Executioner" [] +@PointClass size(-16 -16 -32, 16 16 40) model({"path": "models/enemies/fallen/fallen1.md3"}) = monster_fallen : "Monster: Fallen" [] +@PointClass size(-48 -48 -48, 48 48 48) model({"path": "models/enemies/heretic/heretic.md3"}) = monster_heretic : "Monster: Heretic" [] +@PointClass size(-32 -32 -32, 32 32 48) model({"path": "models/enemies/invader/invader.md3"}) = monster_invader : "Monster: Invader" [] +@PointClass size(-24 -24 -0, 24 24 80) model({"path": "models/enemies/oppressor/oppressor.md3"}) = monster_oppressor : "Monster: Oppressor" [] +@PointClass size(-56 -56 -32, 56 56 64) model({"path": "models/enemies/stricken/stricken.md3"}) = monster_stricken : "Monster: Stricken" [] +@PointClass size(-16 -16 -32, 16 16 32) model({"path": "models/enemies/widow/widow.md3"}) = monster_widow : "Monster: Widow" [] +@PointClass size(-16 -16 -32, 16 16 32) model({"path": "models/enemies/wraith/wraith.md3"}) = monster_wraith : "Monster: Wraith" [] +@PointClass size(-24 -24 -32, 24 24 48) model({"path": "models/enemies/wretch/wretch.md3"}) = monster_wretch : "Monster: Wretch" [] + +// Weapon_* +@PointClass size(-16 -16 -16, 16 16 16) model({"path": "models/weapons/cannon/w_cannon.md3"}) = weapon_cannon : "Cannon" [] +@PointClass size(-16 -16 -16, 16 16 16) model({"path": "models/weapons/coachgun/w_coachgun.md3"}) = weapon_coachgun : "Coach gun" [] +@PointClass size(-16 -16 -16, 16 16 16) model({"path": "models/weapons/spitter/w_spitter.md3"}) = weapon_spitter : "Spitter gun" [] +@PointClass size(-16 -16 -16, 16 16 16) model({"path": "models/weapons/shotgun/w_shotgun.md3"}) = weapon_shotgun : "Shotgun" [] +@PointClass size(-16 -16 -16, 16 16 16) model({"path": "models/weapons/retcher/w_retcher.md3"}) = weapon_retcher : "Retcher" [] + +// Ammo_* +@PointClass size(-16 -16 -10, 16 16 6) model({"path": "models/items/cysts.md3"}) = ammo_cysts : "Retcher ammo" [] +@PointClass size(-8 -8 -10, 8 8 14) model({"path": "models/items/fangs.md3"}) = ammo_fangs : "Spitter ammo" [] +@PointClass size(-16 -16 -8, 16 16 8) model({"path": "models/items/shells.md3"}) = ammo_shells : "Shotgun ammo" [] +@PointClass size(-16 -16 -8, 16 16 8) model({"path": "models/items/slugs.md3"}) = ammo_slugs : "Coachgun ammo" [] +@PointClass size(-8 -8 -11, 8 8 13) model({"path": "models/items/ore.md3"}) = ammo_ore : "Cannon ammo" [] + + +// func_* +@SolidClass = func_door : "Door made of brushes" +[ + noise(string) : "door knock" : "doors/e1_door1.ogg" + noise1(string) : "door start sound" : "doors/glyph_start.ogg" + noise2(string) : "door stop sound" : "doors/glyph_stop.ogg" + _minlight(integer) : "Description" : 64 + speed(integer) : "Description" : 16 + notouch(integer) : "Description" : 1 + lip(integer) : "Description" : -2 + wait(integer) : "Description" : -1 + targetname(string) : "Description" : "opensesame" + target(string) : "Description" : "RedDoor3" + keyrequired(integer) : "Description" : 0 + radius(integer) : "Description" : 2048 + rad_sound(integer) : "Description" : 2048 + spawnflags(integer) : "Description" : 1 +] + +@SolidClass = func_button : "brush entity" +[ + noise(string) : "Description" : "objects/switches/e1m2_pillar_switch.ogg" + target(string) : "Description" : "RedKeyPillarRelay1" + wait(integer) : "Description" : -1 + delay(string) : "Description" : "0.2" + lip(integer) : "Description" : -2 +] + +@SolidClass = func_train : "Trains are moving solids(brush(s)) that follow a looped string of path_corner entities." +[ + _minlight(integer) : "Description" : 72 + sounds(integer) : "Description" : 0 + speed(integer) : "Description" : 440 + target(string) : "Description" : "Pillar4" + targetname(string) : "Description" : "RedKeyPillar1" +] + +@SolidClass = func_rotate : "brush entity" +[ + rot_ang_z(string) : "Description" : "112.75" + rot_ang_x(integer) : "Description" : 0 + rot_ang_y(integer) : "Description" : 0 + targetname(string) : "Description" : "DaBridgeBridge" + wait(integer) : "Description" : 10 +] + +// trigger_* +@SolidClass = trigger_turret : "brush entity" [] +@SolidClass = trigger_monsterjump : "brush entity making monsters jump in the direction its angeled." +[ + speed(integer) : "Description" : 128 +] + +@SolidClass = trigger_multiple : "brush entity" +[ + message(string) : "Description" : "I`m triggered" +] + +@PointClass = trigger_counter : "Description" +[ + spawnflags(integer) : "Description" : 1 + targetname(string) : "Description" : "GaucheDroite" + target(string) : "Description" : "Pecores" + count(integer) : "Description" : 2 + delay(integer) : "Description" : 1 +] + +@SolidClass = trigger_changelevel : "Trigger: Change level" +[ + map(string) : "Level name to load" : "hub1" + location(integer) : "Location to spawn to" : 2 +] + +@SolidClass = trigger_melee : "brush entity" [] +@SolidClass = trigger_once : "brush entity" +[ + message(string) : "Description" : "If you can see this you are CHEATING!" + target(string) : "Description" : "BitchAreYouForReal" + delay(string) : "Description" : "1.2" + spawnflags(integer) : "Description" : 1 + targetname(string) : "Description" : "Chaaaaaarge" + disarmed(integer) : "Description" : 1 + player_weapon(integer) : "Description" : 2 +] + +@SolidClass = trigger_shrine : "brush trigger" [] +@SolidClass = trigger_secret : "Description" [] +@SolidClass = trigger_aggro : "Description" +[ + target(string) : "Description" : "BitchAreYouForReal" +] + +@PointClass = trigger_relay : "Description" +[ + targetname(string) : "Description" : "RedKeyBridgeActivate1" + target(string) : "Description" : "RKeyBridge1" + delay(string) : "Description" : "0.5" + spawnflags(integer) : "Description" : 256 +] \ No newline at end of file diff --git a/tools/trenchbroom/glew32.dll b/tools/trenchbroom/glew32.dll new file mode 100644 index 0000000..fb75d25 Binary files /dev/null and b/tools/trenchbroom/glew32.dll differ diff --git a/tools/trenchbroom/images/Add.svg b/tools/trenchbroom/images/Add.svg new file mode 100644 index 0000000..fc233a6 --- /dev/null +++ b/tools/trenchbroom/images/Add.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/tools/trenchbroom/images/AddProtected.png b/tools/trenchbroom/images/AddProtected.png new file mode 100644 index 0000000..85e5d33 Binary files /dev/null and b/tools/trenchbroom/images/AddProtected.png differ diff --git a/tools/trenchbroom/images/AddProtected.svg b/tools/trenchbroom/images/AddProtected.svg new file mode 100644 index 0000000..589769e --- /dev/null +++ b/tools/trenchbroom/images/AddProtected.svg @@ -0,0 +1,71 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/tools/trenchbroom/images/AlignmentLock_off.svg b/tools/trenchbroom/images/AlignmentLock_off.svg new file mode 100644 index 0000000..3d0d041 --- /dev/null +++ b/tools/trenchbroom/images/AlignmentLock_off.svg @@ -0,0 +1,158 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/AlignmentLock_on.svg b/tools/trenchbroom/images/AlignmentLock_on.svg new file mode 100644 index 0000000..ba43c06 --- /dev/null +++ b/tools/trenchbroom/images/AlignmentLock_on.svg @@ -0,0 +1,180 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/AppIcon.png b/tools/trenchbroom/images/AppIcon.png new file mode 100644 index 0000000..e2689e2 Binary files /dev/null and b/tools/trenchbroom/images/AppIcon.png differ diff --git a/tools/trenchbroom/images/BrushTool.svg b/tools/trenchbroom/images/BrushTool.svg new file mode 100644 index 0000000..aeed52a --- /dev/null +++ b/tools/trenchbroom/images/BrushTool.svg @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/CircleEdgeAligned.svg b/tools/trenchbroom/images/CircleEdgeAligned.svg new file mode 100644 index 0000000..1e3365d --- /dev/null +++ b/tools/trenchbroom/images/CircleEdgeAligned.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/tools/trenchbroom/images/CircleScalable.svg b/tools/trenchbroom/images/CircleScalable.svg new file mode 100644 index 0000000..e4e3f2a --- /dev/null +++ b/tools/trenchbroom/images/CircleScalable.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/CircleVertexAligned.svg b/tools/trenchbroom/images/CircleVertexAligned.svg new file mode 100644 index 0000000..fd73fb4 --- /dev/null +++ b/tools/trenchbroom/images/CircleVertexAligned.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/tools/trenchbroom/images/ClipTool.svg b/tools/trenchbroom/images/ClipTool.svg new file mode 100644 index 0000000..71ad46a --- /dev/null +++ b/tools/trenchbroom/images/ClipTool.svg @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/ColorPreferences.svg b/tools/trenchbroom/images/ColorPreferences.svg new file mode 100644 index 0000000..6bce328 --- /dev/null +++ b/tools/trenchbroom/images/ColorPreferences.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tools/trenchbroom/images/Conflict.svg b/tools/trenchbroom/images/Conflict.svg new file mode 100644 index 0000000..d969dad --- /dev/null +++ b/tools/trenchbroom/images/Conflict.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/tools/trenchbroom/images/DefaultGameIcon.svg b/tools/trenchbroom/images/DefaultGameIcon.svg new file mode 100644 index 0000000..e10743e --- /dev/null +++ b/tools/trenchbroom/images/DefaultGameIcon.svg @@ -0,0 +1,83 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + ? + + diff --git a/tools/trenchbroom/images/DocIcon.png b/tools/trenchbroom/images/DocIcon.png new file mode 100644 index 0000000..f1be818 Binary files /dev/null and b/tools/trenchbroom/images/DocIcon.png differ diff --git a/tools/trenchbroom/images/Down.svg b/tools/trenchbroom/images/Down.svg new file mode 100644 index 0000000..1660a39 --- /dev/null +++ b/tools/trenchbroom/images/Down.svg @@ -0,0 +1,68 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/DuplicateObjects.svg b/tools/trenchbroom/images/DuplicateObjects.svg new file mode 100644 index 0000000..067d821 --- /dev/null +++ b/tools/trenchbroom/images/DuplicateObjects.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/tools/trenchbroom/images/EdgeTool.svg b/tools/trenchbroom/images/EdgeTool.svg new file mode 100644 index 0000000..d058e74 --- /dev/null +++ b/tools/trenchbroom/images/EdgeTool.svg @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/FaceTool.svg b/tools/trenchbroom/images/FaceTool.svg new file mode 100644 index 0000000..0069dc4 --- /dev/null +++ b/tools/trenchbroom/images/FaceTool.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/tools/trenchbroom/images/FlipHorizontally.svg b/tools/trenchbroom/images/FlipHorizontally.svg new file mode 100644 index 0000000..caaf885 --- /dev/null +++ b/tools/trenchbroom/images/FlipHorizontally.svg @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/tools/trenchbroom/images/FlipUAxis.svg b/tools/trenchbroom/images/FlipUAxis.svg new file mode 100644 index 0000000..94eb4a3 --- /dev/null +++ b/tools/trenchbroom/images/FlipUAxis.svg @@ -0,0 +1,73 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/tools/trenchbroom/images/FlipVAxis.svg b/tools/trenchbroom/images/FlipVAxis.svg new file mode 100644 index 0000000..c29a688 --- /dev/null +++ b/tools/trenchbroom/images/FlipVAxis.svg @@ -0,0 +1,71 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/tools/trenchbroom/images/FlipVertically.svg b/tools/trenchbroom/images/FlipVertically.svg new file mode 100644 index 0000000..3affcde --- /dev/null +++ b/tools/trenchbroom/images/FlipVertically.svg @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/tools/trenchbroom/images/Folder.svg b/tools/trenchbroom/images/Folder.svg new file mode 100644 index 0000000..3f2d8f2 --- /dev/null +++ b/tools/trenchbroom/images/Folder.svg @@ -0,0 +1,94 @@ + + + +image/svg+xml diff --git a/tools/trenchbroom/images/GeneralPreferences.svg b/tools/trenchbroom/images/GeneralPreferences.svg new file mode 100644 index 0000000..570532b --- /dev/null +++ b/tools/trenchbroom/images/GeneralPreferences.svg @@ -0,0 +1,68 @@ + +image/svg+xml \ No newline at end of file diff --git a/tools/trenchbroom/images/Hidden_off.svg b/tools/trenchbroom/images/Hidden_off.svg new file mode 100644 index 0000000..4cdf473 --- /dev/null +++ b/tools/trenchbroom/images/Hidden_off.svg @@ -0,0 +1,89 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/Hidden_on.svg b/tools/trenchbroom/images/Hidden_on.svg new file mode 100644 index 0000000..de96fe7 --- /dev/null +++ b/tools/trenchbroom/images/Hidden_on.svg @@ -0,0 +1,76 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/IssueBrowser.svg b/tools/trenchbroom/images/IssueBrowser.svg new file mode 100644 index 0000000..5b2843f --- /dev/null +++ b/tools/trenchbroom/images/IssueBrowser.svg @@ -0,0 +1,82 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/tools/trenchbroom/images/KeyboardPreferences.svg b/tools/trenchbroom/images/KeyboardPreferences.svg new file mode 100644 index 0000000..a0af6e8 --- /dev/null +++ b/tools/trenchbroom/images/KeyboardPreferences.svg @@ -0,0 +1,250 @@ + +image/svg+xml \ No newline at end of file diff --git a/tools/trenchbroom/images/Lock_off.svg b/tools/trenchbroom/images/Lock_off.svg new file mode 100644 index 0000000..cc0cc60 --- /dev/null +++ b/tools/trenchbroom/images/Lock_off.svg @@ -0,0 +1,73 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/tools/trenchbroom/images/Lock_on.svg b/tools/trenchbroom/images/Lock_on.svg new file mode 100644 index 0000000..2ec6333 --- /dev/null +++ b/tools/trenchbroom/images/Lock_on.svg @@ -0,0 +1,74 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/Locked_small.svg b/tools/trenchbroom/images/Locked_small.svg new file mode 100644 index 0000000..d7acd65 --- /dev/null +++ b/tools/trenchbroom/images/Locked_small.svg @@ -0,0 +1,78 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/MousePreferences.svg b/tools/trenchbroom/images/MousePreferences.svg new file mode 100644 index 0000000..acb3956 --- /dev/null +++ b/tools/trenchbroom/images/MousePreferences.svg @@ -0,0 +1,71 @@ + +image/svg+xml \ No newline at end of file diff --git a/tools/trenchbroom/images/NoTool.svg b/tools/trenchbroom/images/NoTool.svg new file mode 100644 index 0000000..484792d --- /dev/null +++ b/tools/trenchbroom/images/NoTool.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/OmitFromExport_off.svg b/tools/trenchbroom/images/OmitFromExport_off.svg new file mode 100644 index 0000000..d5e5ef5 --- /dev/null +++ b/tools/trenchbroom/images/OmitFromExport_off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tools/trenchbroom/images/OmitFromExport_on.svg b/tools/trenchbroom/images/OmitFromExport_on.svg new file mode 100644 index 0000000..3e8b81b --- /dev/null +++ b/tools/trenchbroom/images/OmitFromExport_on.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tools/trenchbroom/images/Protected_small.svg b/tools/trenchbroom/images/Protected_small.svg new file mode 100644 index 0000000..583efb9 --- /dev/null +++ b/tools/trenchbroom/images/Protected_small.svg @@ -0,0 +1,75 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/Refresh.svg b/tools/trenchbroom/images/Refresh.svg new file mode 100644 index 0000000..bc6d640 --- /dev/null +++ b/tools/trenchbroom/images/Refresh.svg @@ -0,0 +1,89 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/Remove.svg b/tools/trenchbroom/images/Remove.svg new file mode 100644 index 0000000..7eb2b99 --- /dev/null +++ b/tools/trenchbroom/images/Remove.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/tools/trenchbroom/images/ResetUV.svg b/tools/trenchbroom/images/ResetUV.svg new file mode 100644 index 0000000..c5f1ffc --- /dev/null +++ b/tools/trenchbroom/images/ResetUV.svg @@ -0,0 +1,76 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/tools/trenchbroom/images/ResetUVToWorld.svg b/tools/trenchbroom/images/ResetUVToWorld.svg new file mode 100644 index 0000000..2b0f11a --- /dev/null +++ b/tools/trenchbroom/images/ResetUVToWorld.svg @@ -0,0 +1,104 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/RotateTool.svg b/tools/trenchbroom/images/RotateTool.svg new file mode 100644 index 0000000..17a9cb8 --- /dev/null +++ b/tools/trenchbroom/images/RotateTool.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/RotateUVCCW.svg b/tools/trenchbroom/images/RotateUVCCW.svg new file mode 100644 index 0000000..2795400 --- /dev/null +++ b/tools/trenchbroom/images/RotateUVCCW.svg @@ -0,0 +1,88 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/RotateUVCW.svg b/tools/trenchbroom/images/RotateUVCW.svg new file mode 100644 index 0000000..3cc057f --- /dev/null +++ b/tools/trenchbroom/images/RotateUVCW.svg @@ -0,0 +1,88 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/ScaleTool.svg b/tools/trenchbroom/images/ScaleTool.svg new file mode 100644 index 0000000..c5925c5 --- /dev/null +++ b/tools/trenchbroom/images/ScaleTool.svg @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/tools/trenchbroom/images/Search.svg b/tools/trenchbroom/images/Search.svg new file mode 100644 index 0000000..5531e3e --- /dev/null +++ b/tools/trenchbroom/images/Search.svg @@ -0,0 +1,106 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/tools/trenchbroom/images/SetDefaultProperties.svg b/tools/trenchbroom/images/SetDefaultProperties.svg new file mode 100644 index 0000000..698d347 --- /dev/null +++ b/tools/trenchbroom/images/SetDefaultProperties.svg @@ -0,0 +1,95 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/tools/trenchbroom/images/ShapeTool_Cone.svg b/tools/trenchbroom/images/ShapeTool_Cone.svg new file mode 100644 index 0000000..6522093 --- /dev/null +++ b/tools/trenchbroom/images/ShapeTool_Cone.svg @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/tools/trenchbroom/images/ShapeTool_Cuboid.svg b/tools/trenchbroom/images/ShapeTool_Cuboid.svg new file mode 100644 index 0000000..ac11051 --- /dev/null +++ b/tools/trenchbroom/images/ShapeTool_Cuboid.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/tools/trenchbroom/images/ShapeTool_Cylinder.svg b/tools/trenchbroom/images/ShapeTool_Cylinder.svg new file mode 100644 index 0000000..c904bcd --- /dev/null +++ b/tools/trenchbroom/images/ShapeTool_Cylinder.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/tools/trenchbroom/images/ShapeTool_IcoSphere.svg b/tools/trenchbroom/images/ShapeTool_IcoSphere.svg new file mode 100644 index 0000000..2d96064 --- /dev/null +++ b/tools/trenchbroom/images/ShapeTool_IcoSphere.svg @@ -0,0 +1,101 @@ + + + +image/svg+xml diff --git a/tools/trenchbroom/images/ShapeTool_UVSphere.svg b/tools/trenchbroom/images/ShapeTool_UVSphere.svg new file mode 100644 index 0000000..2949f11 --- /dev/null +++ b/tools/trenchbroom/images/ShapeTool_UVSphere.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/ShearTool.svg b/tools/trenchbroom/images/ShearTool.svg new file mode 100644 index 0000000..99f4b91 --- /dev/null +++ b/tools/trenchbroom/images/ShearTool.svg @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/tools/trenchbroom/images/UVLock_off.svg b/tools/trenchbroom/images/UVLock_off.svg new file mode 100644 index 0000000..e898015 --- /dev/null +++ b/tools/trenchbroom/images/UVLock_off.svg @@ -0,0 +1,159 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/UVLock_on.svg b/tools/trenchbroom/images/UVLock_on.svg new file mode 100644 index 0000000..e8c9795 --- /dev/null +++ b/tools/trenchbroom/images/UVLock_on.svg @@ -0,0 +1,173 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/Up.svg b/tools/trenchbroom/images/Up.svg new file mode 100644 index 0000000..0e9d64d --- /dev/null +++ b/tools/trenchbroom/images/Up.svg @@ -0,0 +1,65 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/tools/trenchbroom/images/VertexTool.svg b/tools/trenchbroom/images/VertexTool.svg new file mode 100644 index 0000000..b21af62 --- /dev/null +++ b/tools/trenchbroom/images/VertexTool.svg @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/tools/trenchbroom/images/ViewPreferences.svg b/tools/trenchbroom/images/ViewPreferences.svg new file mode 100644 index 0000000..c8d0488 --- /dev/null +++ b/tools/trenchbroom/images/ViewPreferences.svg @@ -0,0 +1,89 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/tools/trenchbroom/images/credits.md b/tools/trenchbroom/images/credits.md new file mode 100644 index 0000000..6e6f4f7 --- /dev/null +++ b/tools/trenchbroom/images/credits.md @@ -0,0 +1,6 @@ +# Font Awesome Free 5.15.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + +- ColorPreferences.svg (was solid/palette.svg) +- OmitFromExport_off.svg (was regular/circle.svg) +- OmitFromExport_on.svg (was regular/times-circle.svg) +- ResetUVToWorld.svg (was solid/globe.svg) diff --git a/tools/trenchbroom/jpeg62.dll b/tools/trenchbroom/jpeg62.dll new file mode 100644 index 0000000..b9ec5f3 Binary files /dev/null and b/tools/trenchbroom/jpeg62.dll differ diff --git a/tools/trenchbroom/lcms2.dll b/tools/trenchbroom/lcms2.dll new file mode 100644 index 0000000..8f23348 Binary files /dev/null and b/tools/trenchbroom/lcms2.dll differ diff --git a/tools/trenchbroom/liblzma.dll b/tools/trenchbroom/liblzma.dll new file mode 100644 index 0000000..6d753cd Binary files /dev/null and b/tools/trenchbroom/liblzma.dll differ diff --git a/tools/trenchbroom/libpng16.dll b/tools/trenchbroom/libpng16.dll new file mode 100644 index 0000000..7e90f84 Binary files /dev/null and b/tools/trenchbroom/libpng16.dll differ diff --git a/tools/trenchbroom/libsharpyuv.dll b/tools/trenchbroom/libsharpyuv.dll new file mode 100644 index 0000000..0d72347 Binary files /dev/null and b/tools/trenchbroom/libsharpyuv.dll differ diff --git a/tools/trenchbroom/libwebp.dll b/tools/trenchbroom/libwebp.dll new file mode 100644 index 0000000..e35eb04 Binary files /dev/null and b/tools/trenchbroom/libwebp.dll differ diff --git a/tools/trenchbroom/libwebpdecoder.dll b/tools/trenchbroom/libwebpdecoder.dll new file mode 100644 index 0000000..ab61cd7 Binary files /dev/null and b/tools/trenchbroom/libwebpdecoder.dll differ diff --git a/tools/trenchbroom/libwebpmux.dll b/tools/trenchbroom/libwebpmux.dll new file mode 100644 index 0000000..d75c3ac Binary files /dev/null and b/tools/trenchbroom/libwebpmux.dll differ diff --git a/tools/trenchbroom/manual/_reset.css b/tools/trenchbroom/manual/_reset.css new file mode 100644 index 0000000..e409e62 --- /dev/null +++ b/tools/trenchbroom/manual/_reset.css @@ -0,0 +1,33 @@ +/* ##### Reset ########## */ + +html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: unset; + vertical-align: baseline; + box-sizing: border-box; +} + +body { + line-height: 1; +} + +ol, ul { + list-style: none; +} + +blockquote, q { + quotes: none; +} + +blockquote::before, blockquote::after, q::before, q::after { + content: ''; + content: none; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} diff --git a/tools/trenchbroom/manual/_responsive.css b/tools/trenchbroom/manual/_responsive.css new file mode 100644 index 0000000..2e6c6e2 --- /dev/null +++ b/tools/trenchbroom/manual/_responsive.css @@ -0,0 +1,95 @@ +/* ##### Responsive ########## */ + +@media only screen and (max-width: 1024px) { + /* Code, Figure and Table */ + + pre, figure, table { + max-width: max-content; + margin-left: auto; + margin-right: auto; + } + + /* List */ + + dl dd { + margin-left: var(--spacing-x15000); + } + + ol, ul { + margin-left: var(--spacing-x15000); + } + + /* Figure */ + + figure { + display: block; + } + + /* Image */ + + p img { + display: block; + float: inherit; + margin: 0 auto var(--spacing-x10000); + } + + /* Table of Contents and Content */ + + body #toc_toggler, body #toc, body #content { + padding: var(--spacing-x10000); + } + + /* Table of Contents & Content */ + + body #toc, body #content { + margin-left: 50px; + } + + /* Table of Contents */ + + body #toc_toggler { + display: flex; + } + + body #toc { + display: none; + min-width: calc(100vw - 50px); + max-width: calc(100vw - 50px); + right: 0; + } + + body.toc_toggled #toc { + display: block; + } + + /* Content Version */ + + body #content_version #content_version_details img { + display: none; + } + + body #content_version #content_version_details div, body #content_version #content_version_links { + align-items: center; + } + + body #content_version { + flex-direction: column; + } + + body #content_version #content_version_links { + margin-top: var(--spacing-x05000); + margin-left: inherit; + } + + /* Content Body */ + + body #content_body { + margin: 0; + } + + /* Back to Top */ + + body #content a[href="#"] { + display: none; + } +} diff --git a/tools/trenchbroom/manual/_specific.css b/tools/trenchbroom/manual/_specific.css new file mode 100644 index 0000000..222a976 --- /dev/null +++ b/tools/trenchbroom/manual/_specific.css @@ -0,0 +1,223 @@ +/* ##### Specific ########## */ + +/* All */ + +* { + outline: none; +} + +/* Code */ + +pre { + max-width: max-content; + padding: var(--spacing-x10000); + margin-left: var(--spacing-x10000); + margin-right: var(--spacing-x10000); + line-height: var(--typography-line-height-tight); + overflow-x: auto; + overflow-y: hidden; + border: var(--border); + border-radius: var(--border-radius-25); + background-color: var(--color-gray-97); +} + +code { + font-family: var(--typography-font-family-code); + font-size: var(--typography-font-size-x07500); + word-break: break-word; +} + +/* Typography */ + +h1, h2, h3, h4 { + font-weight: var(--typography-font-weight-bold); +} + +h1 { + font-size: var(--typography-font-size-x20000); +} + +h2 { + font-size: var(--typography-font-size-x15000); +} + +h3, h4 { + font-size: var(--typography-font-size-x12500); +} + +p { + text-align: justify; +} + +b, strong { + font-weight: var(--typography-font-weight-bold); +} + +i, em { + font-style: italic; +} + +/* List */ + +dl dt { + font-weight: var(--typography-font-weight-bold); +} + +dl dd { + margin-left: var(--spacing-x20000); +} + +ol, ul { + margin-left: var(--spacing-x20000); +} + +ol { + list-style-type: decimal; +} + +ul { + list-style-type: disc; +} + +ul > li > ul:not(:first-child) { + margin-top: var(--spacing-x05000); + margin-bottom: var(--spacing-x05000); +} + +ul > li > ul > li { + list-style-type: circle; +} + +ul > li > ul > li > ul > li { + list-style-type: square; +} + +/* Link */ + +a:link, a:visited { + text-decoration: none; + color: var(--color-azureradiance); +} + +a:hover, a:focus { + text-decoration: underline; +} + +/* Figure */ + +figure { + display: inline-block; + margin-left: var(--spacing-x10000); + margin-right: var(--spacing-x10000); + border-radius: var(--border-radius-25); + background-color: var(--color-gray-97); +} + +figure figcaption { + padding: var(--spacing-x05000) 0; + font-size: var(--typography-font-size-x07500); + font-weight: var(--typography-font-weight-bold); + text-align: center; + color: var(--color-gray-20); +} + +/* Image */ + +figure img { + display: block; + max-width: 100%; + margin: 0; + border-radius: var(--border-radius-25); + background-color: var(--color-gray-97); +} + +p img { + float: left; + max-width: 100%; + margin: 0 var(--spacing-x10000) var(--spacing-x10000) 0; +} + +/* Table */ + +table { + display: block; + margin-left: var(--spacing-x10000); + margin-right: var(--spacing-x10000); + white-space: nowrap; + overflow-x: auto; +} + +table colgroup col { + width: unset !important; +} + +table tr th, table tr td { + padding: var(--spacing-x05000); + vertical-align: middle; + border: var(--border); +} + +table thead tr th { + font-weight: var(--typography-font-weight-bold); + text-align: left; +} + +table tbody tr.odd { + background-color: var(--color-gray-97); +} + +/* Shortcut */ + +.shortcut { + display: inline-block; + min-width: var(--sizing-x15000); + margin: 0 var(--spacing-x00625); + padding: var(--spacing-x00625) var(--spacing-x02500); + font-size: var(--typography-font-size-x07500); + font-family: var(--typography-font-family-base); + font-weight: var(--typography-font-weight-bold); + text-align: center; + border: var(--border); + border-radius: var(--border-radius-25); + background-color: var(--color-gray-97); +} + +/* Line Break */ + +br { + display: none; +} + +/* Space */ + +h1, h2, h3, h4, img, ul, ol, dl, p, pre, table, figure { + margin-bottom: var(--spacing-x10000); +} + +/* Back to Top & Table of Contents anchors */ + +.toc_toggler_button { + cursor: pointer; + border: none; +} + +a[href="#"], .toc_toggler_button { + display: flex; + align-items: center; + justify-content: center; + width: var(--sizing-x20000); + height: var(--sizing-x20000); + font-size: var(--typography-font-size-x12500); + text-decoration: none; + border-radius: 50%; + background-color: var(--color-gray-100); + color: var(--color-gray-20); +} + +a[href="#"]:hover, a[href="#"]:focus, .toc_toggler_button:hover, .toc_toggler_button:focus { + background-color: var(--color-gray-97); +} + +a[href="#"] span, .toc_toggler_button span { + line-height: var(--typography-line-height-reset); +} diff --git a/tools/trenchbroom/manual/_specific.darkmode.css b/tools/trenchbroom/manual/_specific.darkmode.css new file mode 100644 index 0000000..a660172 --- /dev/null +++ b/tools/trenchbroom/manual/_specific.darkmode.css @@ -0,0 +1,54 @@ +/* ##### Specific: Dark Mode ########## */ + +@media (prefers-color-scheme: dark) { + /* Code */ + + pre { + background-color: var(--color-gray-15); + } + + /* Link */ + + a:link, a:visited { + color: var(--color-maximumyellowred); + } + + /* Figure */ + + figure { + background-color: var(--color-gray-15); + } + + figure figcaption { + color: var(--color-gray-90); + } + + /* Image */ + + figure img { + background-color: var(--color-gray-15); + } + + /* Table */ + + table tbody tr.odd { + background-color: var(--color-gray-15); + } + + /* Shortcut */ + + .shortcut { + background-color: var(--color-gray-15); + } + + /* Back to Top & Table of Contents anchors */ + + a[href="#"], .toc_toggler_button { + background-color: var(--color-gray-15); + color: var(--color-gray-90); + } + + a[href="#"]:hover, a[href="#"]:focus, .toc_toggler_button:hover, .toc_toggler_button:focus { + background-color: var(--color-gray-20); + } +} diff --git a/tools/trenchbroom/manual/_variables.css b/tools/trenchbroom/manual/_variables.css new file mode 100644 index 0000000..1a18713 --- /dev/null +++ b/tools/trenchbroom/manual/_variables.css @@ -0,0 +1,61 @@ +/* ##### Variables ########## */ + +:root { + /* Typography */ + + --typography-font-family-base: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + --typography-font-family-code: 'Lucida Console', Monaco, monospace; + --typography-font-size-x07500: calc(var(--typography-font-size-x10000) * 0.75); + --typography-font-size-x08750: calc(var(--typography-font-size-x10000) * 0.875); + --typography-font-size-x10000: 16px; + --typography-font-size-x11250: calc(var(--typography-font-size-x10000) * 1.125); + --typography-font-size-x12500: calc(var(--typography-font-size-x10000) * 1.25); + --typography-font-size-x15000: calc(var(--typography-font-size-x10000) * 1.5); + --typography-font-size-x20000: calc(var(--typography-font-size-x10000) * 2); + --typography-font-weight-regular: 400; + --typography-font-weight-bold: 700; + --typography-line-height-reset: 1; + --typography-line-height-tight: 1.2; + --typography-line-height-normal: 1.6; + + /* Colors */ + + --color-gray-5: hsl(0, 0%, 5%); + --color-gray-20: hsl(0, 0%, 20%); + --color-gray-40: hsl(0, 0%, 40%); + --color-gray-60: hsl(0, 0%, 60%); + --color-gray-80: hsl(0, 0%, 80%); + --color-gray-97: hsl(0, 0%, 97%); + --color-gray-100: hsl(0, 0%, 100%); + --color-azureradiance: hsl(210, 100%, 50%); + + /* Borders */ + + --border: var(--sizing-x00625) solid var(--color-gray-80); + --border-radius-25: var(--sizing-x02500); + + /* Sizing */ + + --sizing-x00625: calc(var(--sizing-x10000) * 0.0625); + --sizing-x02500: calc(var(--sizing-x10000) * 0.25); + --sizing-x05000: calc(var(--sizing-x10000) * 0.5); + --sizing-x10000: 16px; + --sizing-x12500: calc(var(--sizing-x10000) * 1.25); + --sizing-x15000: calc(var(--sizing-x10000) * 1.5); + --sizing-x20000: calc(var(--sizing-x10000) * 2); + --sizing-x30000: calc(var(--sizing-x10000) * 3); + + /* Spacing */ + + --spacing-x00625: calc(var(--spacing-x10000) * 0.0625); + --spacing-x02500: calc(var(--spacing-x10000) * 0.25); + --spacing-x05000: calc(var(--spacing-x10000) * 0.5); + --spacing-x10000: 16px; + --spacing-x15000: calc(var(--spacing-x10000) * 1.5); + --spacing-x20000: calc(var(--spacing-x10000) * 2); + + /* Custom Sizes */ + + --toc-width: max-content; + --content-max-width: 1280px; +} diff --git a/tools/trenchbroom/manual/_variables.darkmode.css b/tools/trenchbroom/manual/_variables.darkmode.css new file mode 100644 index 0000000..e86987d --- /dev/null +++ b/tools/trenchbroom/manual/_variables.darkmode.css @@ -0,0 +1,16 @@ +/* ##### Variables: Dark Mode ########## */ + +@media (prefers-color-scheme: dark) { + :root { + /* Colors */ + + --color-gray-10: hsl(0, 0%, 10%); + --color-gray-15: hsl(0, 0%, 15%); + --color-gray-90: hsl(0, 0%, 90%); + --color-maximumyellowred: hsl(40, 90%, 60%); + + /* Borders */ + + --border: var(--sizing-x00625) solid var(--color-gray-40); + } +} diff --git a/tools/trenchbroom/manual/default.css b/tools/trenchbroom/manual/default.css new file mode 100644 index 0000000..25cc08d --- /dev/null +++ b/tools/trenchbroom/manual/default.css @@ -0,0 +1,160 @@ +/* ##### Default ########## */ + +/* Body */ + +body { + display: flex; + font-family: var(--typography-font-family-base); + font-size: var(--typography-font-size-x10000); + font-weight: var(--typography-font-weight-regular); + line-height: var(--typography-line-height-normal); + background-color: var(--color-gray-100); + color: var(--color-gray-20); +} + +body.toc_toggled { + overflow: hidden; +} + +/* Table of Contents and Content */ + +body #toc_toggler, +body #toc, +body #content { + padding: var(--spacing-x20000); +} + +/* Table of Contents */ + +body #toc_toggler, +body #toc { + background-color: var(--color-gray-97); + box-shadow: 16px 0 24px -12px var(--color-gray-80); +} + +body #toc_toggler { + display: none; + flex-direction: column; + align-items: center; + min-width: 50px; + max-width: 50px; + position: fixed; + top: 0; + bottom: 0; +} + +body #toc_toggler img { + width: var(--sizing-x12500); + height: var(--sizing-x12500); +} + +body #toc_toggler>a[href="#"] { + margin-top: auto; +} + +body #toc { + height: 100vh; + min-width: var(--toc-width); + max-width: var(--toc-width); + position: sticky; + top: 0; + left: 0; + bottom: 0; + overflow-y: auto; +} + +body #toc #toc_inner>ul { + margin-top: var(--spacing-x05000); + margin-bottom: 0; + margin-left: 0; + list-style-type: none; +} + +body #toc #toc_inner>ul>li>a { + font-size: var(--typography-font-size-x11250); + font-weight: var(--typography-font-weight-bold); +} + +/* Content */ + +body #content { + display: flex; + flex-direction: column; + flex: 1; + overflow: hidden; +} + +body #content> :last-child { + margin-bottom: 0; +} + +body #content h1, +body #content h2, +body #content h3, +body #content h4 { + display: inline-block; + width: 100%; + margin-top: var(--spacing-x05000); +} + +/* Content Version */ + +body #content_version { + display: flex; + align-items: center; + margin-bottom: var(--spacing-x10000); + padding-bottom: var(--spacing-x05000); + font-size: var(--typography-font-size-x08750); + color: var(--color-gray-60); + border-bottom: var(--border); +} + +body #content_version #content_version_details { + display: flex; + align-items: center; +} + +body #content_version #content_version_details img { + max-width: var(--sizing-x30000); + margin: 0; + margin-right: var(--spacing-x05000); +} + +body #content_version #content_version_details div { + display: flex; + flex-direction: column; +} + +body #content_version #content_version_details div #content_version_heading { + font-size: var(--typography-font-size-x11250); + font-weight: var(--typography-font-weight-bold); + color: var(--color-gray-40); +} + +body #content_version #content_version_links { + display: flex; + flex-direction: column; + align-items: flex-end; + margin-left: auto; +} + +/* Content Body */ + +body #content_body { + width: 100%; + max-width: var(--content-max-width); + align-self: center; +} + +/* Back to Top */ + +body #content a[href="#"] { + position: fixed; + right: var(--spacing-x20000); + bottom: var(--spacing-x20000); +} + +td>img { + margin-bottom: 0; + vertical-align: middle; +} \ No newline at end of file diff --git a/tools/trenchbroom/manual/default.darkmode.css b/tools/trenchbroom/manual/default.darkmode.css new file mode 100644 index 0000000..7cd88a1 --- /dev/null +++ b/tools/trenchbroom/manual/default.darkmode.css @@ -0,0 +1,23 @@ +/* ##### Default: Dark Mode ########## */ + +@media (prefers-color-scheme: dark) { + /* Body */ + + body { + background-color: var(--color-gray-10); + color: var(--color-gray-90); + } + + /* Content Version */ + + body #content_version #content_version_details div #content_version_heading { + color: var(--color-gray-80); + } + + /* Table of Contents */ + + body #toc_toggler, body #toc { + background-color: var(--color-gray-15); + box-shadow: 16px 0 24px -12px var(--color-gray-5); + } +} diff --git a/tools/trenchbroom/manual/images/AxisRestriction.png b/tools/trenchbroom/manual/images/AxisRestriction.png new file mode 100644 index 0000000..f661a97 Binary files /dev/null and b/tools/trenchbroom/manual/images/AxisRestriction.png differ diff --git a/tools/trenchbroom/manual/images/BrushFaceSelection.png b/tools/trenchbroom/manual/images/BrushFaceSelection.png new file mode 100644 index 0000000..3a8f23b Binary files /dev/null and b/tools/trenchbroom/manual/images/BrushFaceSelection.png differ diff --git a/tools/trenchbroom/manual/images/CSGConvexMerge.gif b/tools/trenchbroom/manual/images/CSGConvexMerge.gif new file mode 100644 index 0000000..476ad97 Binary files /dev/null and b/tools/trenchbroom/manual/images/CSGConvexMerge.gif differ diff --git a/tools/trenchbroom/manual/images/CSGHollow.gif b/tools/trenchbroom/manual/images/CSGHollow.gif new file mode 100644 index 0000000..c35b0ca Binary files /dev/null and b/tools/trenchbroom/manual/images/CSGHollow.gif differ diff --git a/tools/trenchbroom/manual/images/CSGIntersect.gif b/tools/trenchbroom/manual/images/CSGIntersect.gif new file mode 100644 index 0000000..802cbe4 Binary files /dev/null and b/tools/trenchbroom/manual/images/CSGIntersect.gif differ diff --git a/tools/trenchbroom/manual/images/CSGSubtractArch.gif b/tools/trenchbroom/manual/images/CSGSubtractArch.gif new file mode 100644 index 0000000..cde430e Binary files /dev/null and b/tools/trenchbroom/manual/images/CSGSubtractArch.gif differ diff --git a/tools/trenchbroom/manual/images/CSGTexturing.gif b/tools/trenchbroom/manual/images/CSGTexturing.gif new file mode 100644 index 0000000..9413e26 Binary files /dev/null and b/tools/trenchbroom/manual/images/CSGTexturing.gif differ diff --git a/tools/trenchbroom/manual/images/CTF1Bounds.png b/tools/trenchbroom/manual/images/CTF1Bounds.png new file mode 100644 index 0000000..f6a9f0e Binary files /dev/null and b/tools/trenchbroom/manual/images/CTF1Bounds.png differ diff --git a/tools/trenchbroom/manual/images/CircleEdgeAligned.png b/tools/trenchbroom/manual/images/CircleEdgeAligned.png new file mode 100644 index 0000000..98cc3e3 Binary files /dev/null and b/tools/trenchbroom/manual/images/CircleEdgeAligned.png differ diff --git a/tools/trenchbroom/manual/images/CircleScalable.png b/tools/trenchbroom/manual/images/CircleScalable.png new file mode 100644 index 0000000..945ac43 Binary files /dev/null and b/tools/trenchbroom/manual/images/CircleScalable.png differ diff --git a/tools/trenchbroom/manual/images/CircleVertexAligned.png b/tools/trenchbroom/manual/images/CircleVertexAligned.png new file mode 100644 index 0000000..a8bee12 Binary files /dev/null and b/tools/trenchbroom/manual/images/CircleVertexAligned.png differ diff --git a/tools/trenchbroom/manual/images/ClipModes.png b/tools/trenchbroom/manual/images/ClipModes.png new file mode 100644 index 0000000..650539a Binary files /dev/null and b/tools/trenchbroom/manual/images/ClipModes.png differ diff --git a/tools/trenchbroom/manual/images/Compass3D.png b/tools/trenchbroom/manual/images/Compass3D.png new file mode 100644 index 0000000..faeb7fa Binary files /dev/null and b/tools/trenchbroom/manual/images/Compass3D.png differ diff --git a/tools/trenchbroom/manual/images/CompilationDialog.png b/tools/trenchbroom/manual/images/CompilationDialog.png new file mode 100644 index 0000000..a999351 Binary files /dev/null and b/tools/trenchbroom/manual/images/CompilationDialog.png differ diff --git a/tools/trenchbroom/manual/images/CompilationDialogToolVars.png b/tools/trenchbroom/manual/images/CompilationDialogToolVars.png new file mode 100644 index 0000000..8784edc Binary files /dev/null and b/tools/trenchbroom/manual/images/CompilationDialogToolVars.png differ diff --git a/tools/trenchbroom/manual/images/CreateBrushByDuplicatingPolygon.gif b/tools/trenchbroom/manual/images/CreateBrushByDuplicatingPolygon.gif new file mode 100644 index 0000000..9cb3db8 Binary files /dev/null and b/tools/trenchbroom/manual/images/CreateBrushByDuplicatingPolygon.gif differ diff --git a/tools/trenchbroom/manual/images/CreateEntityContextMenu.png b/tools/trenchbroom/manual/images/CreateEntityContextMenu.png new file mode 100644 index 0000000..92120de Binary files /dev/null and b/tools/trenchbroom/manual/images/CreateEntityContextMenu.png differ diff --git a/tools/trenchbroom/manual/images/DrawBrush.gif b/tools/trenchbroom/manual/images/DrawBrush.gif new file mode 100644 index 0000000..e2482f4 Binary files /dev/null and b/tools/trenchbroom/manual/images/DrawBrush.gif differ diff --git a/tools/trenchbroom/manual/images/DrillSelection.gif b/tools/trenchbroom/manual/images/DrillSelection.gif new file mode 100644 index 0000000..5d1cd14 Binary files /dev/null and b/tools/trenchbroom/manual/images/DrillSelection.gif differ diff --git a/tools/trenchbroom/manual/images/DuplicateAndMove.gif b/tools/trenchbroom/manual/images/DuplicateAndMove.gif new file mode 100644 index 0000000..0ce8ba0 Binary files /dev/null and b/tools/trenchbroom/manual/images/DuplicateAndMove.gif differ diff --git a/tools/trenchbroom/manual/images/DuplicateInPlace.gif b/tools/trenchbroom/manual/images/DuplicateInPlace.gif new file mode 100644 index 0000000..d9b2cab Binary files /dev/null and b/tools/trenchbroom/manual/images/DuplicateInPlace.gif differ diff --git a/tools/trenchbroom/manual/images/EdgeTool.png b/tools/trenchbroom/manual/images/EdgeTool.png new file mode 100644 index 0000000..a05544c Binary files /dev/null and b/tools/trenchbroom/manual/images/EdgeTool.png differ diff --git a/tools/trenchbroom/manual/images/EntityBrowser.png b/tools/trenchbroom/manual/images/EntityBrowser.png new file mode 100644 index 0000000..7dff5db Binary files /dev/null and b/tools/trenchbroom/manual/images/EntityBrowser.png differ diff --git a/tools/trenchbroom/manual/images/EntityDefinitionEditor.png b/tools/trenchbroom/manual/images/EntityDefinitionEditor.png new file mode 100644 index 0000000..78cad25 Binary files /dev/null and b/tools/trenchbroom/manual/images/EntityDefinitionEditor.png differ diff --git a/tools/trenchbroom/manual/images/EntityLinkVisualization.png b/tools/trenchbroom/manual/images/EntityLinkVisualization.png new file mode 100644 index 0000000..11ece7d Binary files /dev/null and b/tools/trenchbroom/manual/images/EntityLinkVisualization.png differ diff --git a/tools/trenchbroom/manual/images/EntityPropertyEditor.png b/tools/trenchbroom/manual/images/EntityPropertyEditor.png new file mode 100644 index 0000000..a5456a6 Binary files /dev/null and b/tools/trenchbroom/manual/images/EntityPropertyEditor.png differ diff --git a/tools/trenchbroom/manual/images/EntityPropertyEditorMultiSelection.png b/tools/trenchbroom/manual/images/EntityPropertyEditorMultiSelection.png new file mode 100644 index 0000000..34cc2fb Binary files /dev/null and b/tools/trenchbroom/manual/images/EntityPropertyEditorMultiSelection.png differ diff --git a/tools/trenchbroom/manual/images/ExtrudeTool2DFaceMoving.gif b/tools/trenchbroom/manual/images/ExtrudeTool2DFaceMoving.gif new file mode 100644 index 0000000..6b24936 Binary files /dev/null and b/tools/trenchbroom/manual/images/ExtrudeTool2DFaceMoving.gif differ diff --git a/tools/trenchbroom/manual/images/ExtrudeTool3D.gif b/tools/trenchbroom/manual/images/ExtrudeTool3D.gif new file mode 100644 index 0000000..95bd2cc Binary files /dev/null and b/tools/trenchbroom/manual/images/ExtrudeTool3D.gif differ diff --git a/tools/trenchbroom/manual/images/ExtrudeTool3DMultipleBrushes.gif b/tools/trenchbroom/manual/images/ExtrudeTool3DMultipleBrushes.gif new file mode 100644 index 0000000..3a5410c Binary files /dev/null and b/tools/trenchbroom/manual/images/ExtrudeTool3DMultipleBrushes.gif differ diff --git a/tools/trenchbroom/manual/images/ExtrudeTool3DSplitInwardMode.gif b/tools/trenchbroom/manual/images/ExtrudeTool3DSplitInwardMode.gif new file mode 100644 index 0000000..d04346e Binary files /dev/null and b/tools/trenchbroom/manual/images/ExtrudeTool3DSplitInwardMode.gif differ diff --git a/tools/trenchbroom/manual/images/ExtrudeTool3DSplitMode.gif b/tools/trenchbroom/manual/images/ExtrudeTool3DSplitMode.gif new file mode 100644 index 0000000..f0dbd40 Binary files /dev/null and b/tools/trenchbroom/manual/images/ExtrudeTool3DSplitMode.gif differ diff --git a/tools/trenchbroom/manual/images/FaceAttribsEditor.png b/tools/trenchbroom/manual/images/FaceAttribsEditor.png new file mode 100644 index 0000000..6a489f7 Binary files /dev/null and b/tools/trenchbroom/manual/images/FaceAttribsEditor.png differ diff --git a/tools/trenchbroom/manual/images/FaceTool.png b/tools/trenchbroom/manual/images/FaceTool.png new file mode 100644 index 0000000..bcdea84 Binary files /dev/null and b/tools/trenchbroom/manual/images/FaceTool.png differ diff --git a/tools/trenchbroom/manual/images/GameEngineDialog.png b/tools/trenchbroom/manual/images/GameEngineDialog.png new file mode 100644 index 0000000..6cf2809 Binary files /dev/null and b/tools/trenchbroom/manual/images/GameEngineDialog.png differ diff --git a/tools/trenchbroom/manual/images/GamePreferences.png b/tools/trenchbroom/manual/images/GamePreferences.png new file mode 100644 index 0000000..b54e745 Binary files /dev/null and b/tools/trenchbroom/manual/images/GamePreferences.png differ diff --git a/tools/trenchbroom/manual/images/GameSelectionDialog.png b/tools/trenchbroom/manual/images/GameSelectionDialog.png new file mode 100644 index 0000000..03c24d7 Binary files /dev/null and b/tools/trenchbroom/manual/images/GameSelectionDialog.png differ diff --git a/tools/trenchbroom/manual/images/Inspector.png b/tools/trenchbroom/manual/images/Inspector.png new file mode 100644 index 0000000..6b52e44 Binary files /dev/null and b/tools/trenchbroom/manual/images/Inspector.png differ diff --git a/tools/trenchbroom/manual/images/IssueBrowserContextMenu.png b/tools/trenchbroom/manual/images/IssueBrowserContextMenu.png new file mode 100644 index 0000000..5a8155b Binary files /dev/null and b/tools/trenchbroom/manual/images/IssueBrowserContextMenu.png differ diff --git a/tools/trenchbroom/manual/images/IssueBrowserFilter.png b/tools/trenchbroom/manual/images/IssueBrowserFilter.png new file mode 100644 index 0000000..1955042 Binary files /dev/null and b/tools/trenchbroom/manual/images/IssueBrowserFilter.png differ diff --git a/tools/trenchbroom/manual/images/KeyboardPreferences.png b/tools/trenchbroom/manual/images/KeyboardPreferences.png new file mode 100644 index 0000000..d0fd8bb Binary files /dev/null and b/tools/trenchbroom/manual/images/KeyboardPreferences.png differ diff --git a/tools/trenchbroom/manual/images/LaunchGameEngineDialog.png b/tools/trenchbroom/manual/images/LaunchGameEngineDialog.png new file mode 100644 index 0000000..3ae0110 Binary files /dev/null and b/tools/trenchbroom/manual/images/LaunchGameEngineDialog.png differ diff --git a/tools/trenchbroom/manual/images/LayerEditor.png b/tools/trenchbroom/manual/images/LayerEditor.png new file mode 100644 index 0000000..7d3c757 Binary files /dev/null and b/tools/trenchbroom/manual/images/LayerEditor.png differ diff --git a/tools/trenchbroom/manual/images/Linked2DViewports.gif b/tools/trenchbroom/manual/images/Linked2DViewports.gif new file mode 100644 index 0000000..e7b0248 Binary files /dev/null and b/tools/trenchbroom/manual/images/Linked2DViewports.gif differ diff --git a/tools/trenchbroom/manual/images/LinkedGroups.png b/tools/trenchbroom/manual/images/LinkedGroups.png new file mode 100644 index 0000000..1e363af Binary files /dev/null and b/tools/trenchbroom/manual/images/LinkedGroups.png differ diff --git a/tools/trenchbroom/manual/images/Locking.png b/tools/trenchbroom/manual/images/Locking.png new file mode 100644 index 0000000..4d46d8e Binary files /dev/null and b/tools/trenchbroom/manual/images/Locking.png differ diff --git a/tools/trenchbroom/manual/images/MainWindow.png b/tools/trenchbroom/manual/images/MainWindow.png new file mode 100644 index 0000000..d81aedc Binary files /dev/null and b/tools/trenchbroom/manual/images/MainWindow.png differ diff --git a/tools/trenchbroom/manual/images/MatchingClipPlane.gif b/tools/trenchbroom/manual/images/MatchingClipPlane.gif new file mode 100644 index 0000000..6b0c9f1 Binary files /dev/null and b/tools/trenchbroom/manual/images/MatchingClipPlane.gif differ diff --git a/tools/trenchbroom/manual/images/ModEditor.png b/tools/trenchbroom/manual/images/ModEditor.png new file mode 100644 index 0000000..f5a1ddd Binary files /dev/null and b/tools/trenchbroom/manual/images/ModEditor.png differ diff --git a/tools/trenchbroom/manual/images/MousePreferences.png b/tools/trenchbroom/manual/images/MousePreferences.png new file mode 100644 index 0000000..5291ab7 Binary files /dev/null and b/tools/trenchbroom/manual/images/MousePreferences.png differ diff --git a/tools/trenchbroom/manual/images/MoveBrushesToEntity.png b/tools/trenchbroom/manual/images/MoveBrushesToEntity.png new file mode 100644 index 0000000..5886986 Binary files /dev/null and b/tools/trenchbroom/manual/images/MoveBrushesToEntity.png differ diff --git a/tools/trenchbroom/manual/images/MoveObjectsByOffset.png b/tools/trenchbroom/manual/images/MoveObjectsByOffset.png new file mode 100644 index 0000000..aed3046 Binary files /dev/null and b/tools/trenchbroom/manual/images/MoveObjectsByOffset.png differ diff --git a/tools/trenchbroom/manual/images/MoveTrace.png b/tools/trenchbroom/manual/images/MoveTrace.png new file mode 100644 index 0000000..be17102 Binary files /dev/null and b/tools/trenchbroom/manual/images/MoveTrace.png differ diff --git a/tools/trenchbroom/manual/images/ObjectSelection.gif b/tools/trenchbroom/manual/images/ObjectSelection.gif new file mode 100644 index 0000000..edd7b33 Binary files /dev/null and b/tools/trenchbroom/manual/images/ObjectSelection.gif differ diff --git a/tools/trenchbroom/manual/images/PastePositioning3D.gif b/tools/trenchbroom/manual/images/PastePositioning3D.gif new file mode 100644 index 0000000..07d92fd Binary files /dev/null and b/tools/trenchbroom/manual/images/PastePositioning3D.gif differ diff --git a/tools/trenchbroom/manual/images/ProtectedProperties.png b/tools/trenchbroom/manual/images/ProtectedProperties.png new file mode 100644 index 0000000..7aeee31 Binary files /dev/null and b/tools/trenchbroom/manual/images/ProtectedProperties.png differ diff --git a/tools/trenchbroom/manual/images/ReplaceTexture.png b/tools/trenchbroom/manual/images/ReplaceTexture.png new file mode 100644 index 0000000..69b15ae Binary files /dev/null and b/tools/trenchbroom/manual/images/ReplaceTexture.png differ diff --git a/tools/trenchbroom/manual/images/RotateHandle2D.png b/tools/trenchbroom/manual/images/RotateHandle2D.png new file mode 100644 index 0000000..d11a31a Binary files /dev/null and b/tools/trenchbroom/manual/images/RotateHandle2D.png differ diff --git a/tools/trenchbroom/manual/images/RotateHandle3D.png b/tools/trenchbroom/manual/images/RotateHandle3D.png new file mode 100644 index 0000000..857a87e Binary files /dev/null and b/tools/trenchbroom/manual/images/RotateHandle3D.png differ diff --git a/tools/trenchbroom/manual/images/RotateTool.gif b/tools/trenchbroom/manual/images/RotateTool.gif new file mode 100644 index 0000000..2b232d0 Binary files /dev/null and b/tools/trenchbroom/manual/images/RotateTool.gif differ diff --git a/tools/trenchbroom/manual/images/RotateToolControls.png b/tools/trenchbroom/manual/images/RotateToolControls.png new file mode 100644 index 0000000..bc8d194 Binary files /dev/null and b/tools/trenchbroom/manual/images/RotateToolControls.png differ diff --git a/tools/trenchbroom/manual/images/ScalableCylinderStretch.gif b/tools/trenchbroom/manual/images/ScalableCylinderStretch.gif new file mode 100644 index 0000000..caed61a Binary files /dev/null and b/tools/trenchbroom/manual/images/ScalableCylinderStretch.gif differ diff --git a/tools/trenchbroom/manual/images/ScalableHollowCylinder.png b/tools/trenchbroom/manual/images/ScalableHollowCylinder.png new file mode 100644 index 0000000..b2d90b7 Binary files /dev/null and b/tools/trenchbroom/manual/images/ScalableHollowCylinder.png differ diff --git a/tools/trenchbroom/manual/images/Scale3DCorner.gif b/tools/trenchbroom/manual/images/Scale3DCorner.gif new file mode 100644 index 0000000..8ddda6c Binary files /dev/null and b/tools/trenchbroom/manual/images/Scale3DCorner.gif differ diff --git a/tools/trenchbroom/manual/images/Scale3DEdge.gif b/tools/trenchbroom/manual/images/Scale3DEdge.gif new file mode 100644 index 0000000..2e46f42 Binary files /dev/null and b/tools/trenchbroom/manual/images/Scale3DEdge.gif differ diff --git a/tools/trenchbroom/manual/images/Scale3DSide.gif b/tools/trenchbroom/manual/images/Scale3DSide.gif new file mode 100644 index 0000000..fbb9bd5 Binary files /dev/null and b/tools/trenchbroom/manual/images/Scale3DSide.gif differ diff --git a/tools/trenchbroom/manual/images/Scale3DSideCenter.gif b/tools/trenchbroom/manual/images/Scale3DSideCenter.gif new file mode 100644 index 0000000..b481879 Binary files /dev/null and b/tools/trenchbroom/manual/images/Scale3DSideCenter.gif differ diff --git a/tools/trenchbroom/manual/images/ScaleToolToolbar.png b/tools/trenchbroom/manual/images/ScaleToolToolbar.png new file mode 100644 index 0000000..1a170d1 Binary files /dev/null and b/tools/trenchbroom/manual/images/ScaleToolToolbar.png differ diff --git a/tools/trenchbroom/manual/images/SelectTouching.gif b/tools/trenchbroom/manual/images/SelectTouching.gif new file mode 100644 index 0000000..90dba51 Binary files /dev/null and b/tools/trenchbroom/manual/images/SelectTouching.gif differ diff --git a/tools/trenchbroom/manual/images/SetDefaultPropertiesMenu.png b/tools/trenchbroom/manual/images/SetDefaultPropertiesMenu.png new file mode 100644 index 0000000..1dde54b Binary files /dev/null and b/tools/trenchbroom/manual/images/SetDefaultPropertiesMenu.png differ diff --git a/tools/trenchbroom/manual/images/Shear3DVertical.gif b/tools/trenchbroom/manual/images/Shear3DVertical.gif new file mode 100644 index 0000000..d1d3076 Binary files /dev/null and b/tools/trenchbroom/manual/images/Shear3DVertical.gif differ diff --git a/tools/trenchbroom/manual/images/SmartChoiceEditor.png b/tools/trenchbroom/manual/images/SmartChoiceEditor.png new file mode 100644 index 0000000..5926cf1 Binary files /dev/null and b/tools/trenchbroom/manual/images/SmartChoiceEditor.png differ diff --git a/tools/trenchbroom/manual/images/SmartColorEditor.png b/tools/trenchbroom/manual/images/SmartColorEditor.png new file mode 100644 index 0000000..e22b1df Binary files /dev/null and b/tools/trenchbroom/manual/images/SmartColorEditor.png differ diff --git a/tools/trenchbroom/manual/images/SmartSpawnflagsEditor.png b/tools/trenchbroom/manual/images/SmartSpawnflagsEditor.png new file mode 100644 index 0000000..425d123 Binary files /dev/null and b/tools/trenchbroom/manual/images/SmartSpawnflagsEditor.png differ diff --git a/tools/trenchbroom/manual/images/SmartWadEditor.png b/tools/trenchbroom/manual/images/SmartWadEditor.png new file mode 100644 index 0000000..4212a59 Binary files /dev/null and b/tools/trenchbroom/manual/images/SmartWadEditor.png differ diff --git a/tools/trenchbroom/manual/images/SoftBounds.png b/tools/trenchbroom/manual/images/SoftBounds.png new file mode 100644 index 0000000..3a3d641 Binary files /dev/null and b/tools/trenchbroom/manual/images/SoftBounds.png differ diff --git a/tools/trenchbroom/manual/images/TextureBrowser.png b/tools/trenchbroom/manual/images/TextureBrowser.png new file mode 100644 index 0000000..05cb92c Binary files /dev/null and b/tools/trenchbroom/manual/images/TextureBrowser.png differ diff --git a/tools/trenchbroom/manual/images/TextureCollectionEditor.png b/tools/trenchbroom/manual/images/TextureCollectionEditor.png new file mode 100644 index 0000000..3a6410b Binary files /dev/null and b/tools/trenchbroom/manual/images/TextureCollectionEditor.png differ diff --git a/tools/trenchbroom/manual/images/ToolbarTools.png b/tools/trenchbroom/manual/images/ToolbarTools.png new file mode 100644 index 0000000..0f49e90 Binary files /dev/null and b/tools/trenchbroom/manual/images/ToolbarTools.png differ diff --git a/tools/trenchbroom/manual/images/UVEditor.png b/tools/trenchbroom/manual/images/UVEditor.png new file mode 100644 index 0000000..b0e6ca2 Binary files /dev/null and b/tools/trenchbroom/manual/images/UVEditor.png differ diff --git a/tools/trenchbroom/manual/images/UVEditorToolbar.png b/tools/trenchbroom/manual/images/UVEditorToolbar.png new file mode 100644 index 0000000..a944c90 Binary files /dev/null and b/tools/trenchbroom/manual/images/UVEditorToolbar.png differ diff --git a/tools/trenchbroom/manual/images/UVLock.png b/tools/trenchbroom/manual/images/UVLock.png new file mode 100644 index 0000000..bc3cd6e Binary files /dev/null and b/tools/trenchbroom/manual/images/UVLock.png differ diff --git a/tools/trenchbroom/manual/images/UpdateAnglePropertyAfterTransform.png b/tools/trenchbroom/manual/images/UpdateAnglePropertyAfterTransform.png new file mode 100644 index 0000000..7a14fc6 Binary files /dev/null and b/tools/trenchbroom/manual/images/UpdateAnglePropertyAfterTransform.png differ diff --git a/tools/trenchbroom/manual/images/VertexToolFaceChopping.gif b/tools/trenchbroom/manual/images/VertexToolFaceChopping.gif new file mode 100644 index 0000000..394004a Binary files /dev/null and b/tools/trenchbroom/manual/images/VertexToolFaceChopping.gif differ diff --git a/tools/trenchbroom/manual/images/VertexToolGuide.png b/tools/trenchbroom/manual/images/VertexToolGuide.png new file mode 100644 index 0000000..28ca755 Binary files /dev/null and b/tools/trenchbroom/manual/images/VertexToolGuide.png differ diff --git a/tools/trenchbroom/manual/images/VertexToolHandles.png b/tools/trenchbroom/manual/images/VertexToolHandles.png new file mode 100644 index 0000000..ecb9e43 Binary files /dev/null and b/tools/trenchbroom/manual/images/VertexToolHandles.png differ diff --git a/tools/trenchbroom/manual/images/VertexToolSplitting.gif b/tools/trenchbroom/manual/images/VertexToolSplitting.gif new file mode 100644 index 0000000..d128e4b Binary files /dev/null and b/tools/trenchbroom/manual/images/VertexToolSplitting.gif differ diff --git a/tools/trenchbroom/manual/images/VertexToolVertexClumping.gif b/tools/trenchbroom/manual/images/VertexToolVertexClumping.gif new file mode 100644 index 0000000..0f57cb6 Binary files /dev/null and b/tools/trenchbroom/manual/images/VertexToolVertexClumping.gif differ diff --git a/tools/trenchbroom/manual/images/ViewDropdown.png b/tools/trenchbroom/manual/images/ViewDropdown.png new file mode 100644 index 0000000..1557088 Binary files /dev/null and b/tools/trenchbroom/manual/images/ViewDropdown.png differ diff --git a/tools/trenchbroom/manual/images/ViewPreferences.png b/tools/trenchbroom/manual/images/ViewPreferences.png new file mode 100644 index 0000000..7f2f7c4 Binary files /dev/null and b/tools/trenchbroom/manual/images/ViewPreferences.png differ diff --git a/tools/trenchbroom/manual/images/WelcomeWindow.png b/tools/trenchbroom/manual/images/WelcomeWindow.png new file mode 100644 index 0000000..238979f Binary files /dev/null and b/tools/trenchbroom/manual/images/WelcomeWindow.png differ diff --git a/tools/trenchbroom/manual/images/icon.png b/tools/trenchbroom/manual/images/icon.png new file mode 100644 index 0000000..a937223 Binary files /dev/null and b/tools/trenchbroom/manual/images/icon.png differ diff --git a/tools/trenchbroom/manual/index.html b/tools/trenchbroom/manual/index.html new file mode 100644 index 0000000..4bbde53 --- /dev/null +++ b/tools/trenchbroom/manual/index.html @@ -0,0 +1,3805 @@ + + + + + + + + TrenchBroom 2024.2 Reference Manual + + + + + + + + + + + + + + +
+ TrenchBroom Icon + + +
+ +
+ +
+

Introduction

+

TrenchBroom is a level editing program for brush-based game engines such as Quake, Quake 2, and Hexen 2. TrenchBroom is easy to use and provides many simple and advanced tools to create complex and interesting levels with ease. This document contains the manual for TrenchBroom. Reading this document will teach you how to use TrenchBroom and how to use its advanced features.

+

Features

+
    +
  • General +
      +
    • Full support for editing in 3D and in up to three 2D views
    • +
    • High performance renderer with support for huge maps
    • +
    • Unlimited Undo and Redo
    • +
    • Macro-like command repetition
    • +
    • Linked groups
    • +
    • Issue browser with automatic quick fixes
    • +
    • Run external compilers and launch game engines
    • +
    • Point file support
    • +
    • Portal file support
    • +
    • Automatic backups
    • +
    • Free and cross platform
    • +
  • +
  • Brush Editing +
      +
    • Robust vertex editing with edge and face splitting and manipulating multiple vertices together
    • +
    • Clipping tool with two and three points
    • +
    • Scale and shear tools
    • +
    • CSG operations: merge, subtract, hollow
    • +
    • UV view for easy texturing manipulations
    • +
    • Precise alignment lock for all brush editing operations
    • +
    • Multiple material collections
    • +
  • +
  • Entity Editing +
      +
    • Entity browser with drag and drop support
    • +
    • Support for FGD, ENT and DEF files for entity definitions
    • +
    • Mod support
    • +
    • Entity link visualization
    • +
    • Displays 3D models in the editor (supports mdl, md2, md3, bsp, dkm)
    • +
    • Smart entity property editors
    • +
  • +
+

About this Document

+

This document is intended to help you learn to use the TrenchBroom editor. It is not intended to teach you how to map, and it isn’t a tutorial either. If you are having technical problems with your maps, or need information on how to create particular effects or setups for the particular game you are mapping for, you should ask other mappers for help (see References and Links to find mapping communities and such). This document will only teach you how to use this editor.

+

Getting Started

+

This section starts off with a small introduction to the most important technical terms related to mapping for brush-based engines. Additionally, we introduce some concepts on which TrenchBroom is built. Afterwards, we introduce the welcome window, the game selection dialog, we give an overview of the main window and explain the camera navigation in the 3D and 2D views.

+

Preliminaries

+

In this section we introduce some technical terms related to mapping in Quake-engine based games. It is not important that you understand every detail of all of these terms, but in order to understand how TrenchBroom works, you should have a general idea how maps are structured and how TrenchBroom views and manages that structure. In particular, this section introduces some concepts that we added to the map structures (without changing the file format, of course). Knowing and understanding these concepts will help you to get a grip on several important aspects of editing levels in TrenchBroom.

+

Map Definitions

+

In Quake-engine based games, levels are usually called maps. The following simple specification of the structure of a map is written in extended Backus-Naur-Form (EBNF), a simple syntax to define hierarchical structures that is widely used in computer science to define the syntax of computer languages. Don’t worry, you don’t have to understand EBNF as we will explain the definitions line by line.

+
1. `Map      = Entity {Entity}`
+        2. `Entity   = {Property} {Brush}`
+        3. `Property = Key Value`
+        4. `Brush    = {Face}`
+        5. `Face     = Plane Texture Offset Scale Rotation ...`
+

The first line specifies that a map contains an entity followed by zero or more entities. In EBNF, the braces surrounding the word “Entity” indicate that it stands for a possibly empty sequence of entities. Altogether, line one means that a map is just a sequence of one or more entities. An entity is a possibly empty sequence of properties followed by zero or more brushes. A property is just a key-value pair, and both the key and the value are strings (this information was omitted from the EBNF).

+

Line four defines a Brush as a possibly empty sequence of faces (but usually it will have at least four, otherwise the brush would be invalid). And in line five, we finally define that a Face has a plane, a material, the X and Y offsets and scales, the rotation angle, and possibly other attributes depending on the game.

+

In this document, we use the term object to refer to entities and brushes.

+

TrenchBroom’s View of Maps

+

TrenchBroom organizes the objects of a map a bit differently than how they are organized in the map files. Firstly, TrenchBroom introduces two additional concepts: Layers and Groups. Secondly, the worldspawn entity is hidden from you and its properties are associated with the map. To differentiate TrenchBroom’s view from the view that other tools and compilers have, we use the term “world” instead of “map” here. In the remainder of this document, we will use the term “map” again.

+
1. `World        = {Property} DefaultLayer {Layer}`
+        2. `DefaultLayer = Layer`
+        3. `Layer        = Name {Group} {Entity} {Brush}`
+        4. `Group        = Name {Group} {Entity} {Brush}`
+

The first line defines the structure of a map as TrenchBroom sees it. To TrenchBroom, a World consists of zero or more properties, a default layer, and zero or more additional layers. The second line specifies that the DefaultLayer is just a layer. Then, the third line defines what a Layer is: A layer has a name (just a string), and it contains zero or more groups, zero or more entities, and zero or more brushes. In TrenchBroom, layers are used to partition a map into several large areas in order to reduce visual clutter by hiding them. In contrast, groups are used to merge a small number of objects into one object so that they can all be edited as one. Like layers, a Group is composed of a name, zero or more groups, zero or more entities, and zero or more brushes. In case you didn’t notice, groups induce a hierarchy, that is, a group can contain other sub-groups. All other definitions are exactly the same as in the previous section.

+

To summarize, TrenchBroom sees a map as a hierarchy (a tree). The root of the hierarchy is called world and represents the entire map. The world consists first of layers, then groups, entities, and brushes, whereby groups can contain more groups, entities, and brushes, and entities can again contain brushes. Because groups can contain other groups, the hierarchy can be arbitrarily deep, although in practice groups will rarely contain more than one additional level of sub groups.

+

Brush Geometry

+

In standard map files, the geometry of a brush is defined by a set of faces. Apart from the attributes defining the UV mapping, a face also specifies a plane using three plane points. The plane is oriented by the order in which the three points are written in the face specification in the map file. Here is an example:

+
( 32 32 -3824  ) ( -32 32 -3824  ) ( -32 96 -3824 ) mmetal1_2 0 0 0 1 1
+

The plane points are given as three groups of three numbers. Each group is made up of three numbers that specify the X,Y and Z coordinates of the respective plane point. The three points, p1, p2 and p3, define two vectors, v1 and v2, as follows:

+
  *p2
+         /|\
+          |
+          v2
+          |
+        p1*--v1--->*p3
+

The normal of the plane is in the direction of the cross product of v1 and v2. In the diagram above, the plane normal points towards you. Together with its normal, the plane divides three dimensional space into two half spaces: The upper half space above the plane, and the lower half space below the plane. In this interpretation, the volume of the brush is the intersection of the lower half spaces defined by the face planes. This way of defining brushes has the advantage that all brushes are automatically convex. However, this representation of brushes does not directly contain any other geometric information of the brush, particularly its vertices, edges, and facets, which must be computed from the plane representation. In TrenchBroom, the vertices, edges, and facets are called the brush geometry. TrenchBroom uses the same method as the BSP compilers to compute the brush geometry. Having the brush geometry is necessary mainly for two things: Rendering and vertex editing.

+

Entity Definitions

+

To TrenchBroom, entities are just a sequence of properties (key value pairs), most of which are without any special meaning. In particular, the entity properties do not specify which model TrenchBroom should display for the entity in its viewports. Additionally, some property values have specific types, such as color, angle, or position. But these types cannot be hardcoded into the editor, because depending on the game, mod, or entity, a property called “angle” may have a different meaning. To give TrenchBroom more information on how to interpret a particular entity and its properties, an entity definition is necessary. Entity definitions specify the spawnflags of an entity, the names and types of its properties, the model to display in the editor, and other things. They are usually specified in a separate file that you can load into the editor.

+

Mods

+

A mod (short for game modification) is a way of extending a Quake-engine based game with custom gameplay and assets. Custom assets include models, sounds, and materials. From the perspective of the game, a mod is a subdirectory in the game directory where the additional assets reside in the form of loose files or archives such as pak files. As far as TrenchBroom is concerned, a mod just provides assets, some of which replace existing assets from the game and some of which are new. For example, a mod might provide a new model for an entity, or it provides an entirely new entity. In order to make these new entities usable in TrenchBroom, two things are required: First, TrenchBroom needs an entity definition for these entities, and TrenchBroom needs to know where it should look for the models to display in the viewports. The first issue can be addressed by pointing TrenchBroom to an alternate entity definition file, and the second issue can be addressed by adding a mod directory for the current map.

+

Every game has a default mod which is always loaded by TrenchBroom. As an example, the default mod for Quake is id1, which is the directory that contains all game content. TrenchBroom supports multiple mods, and in the case of multiple mods, there has to be a policy for resolving name conflicts between resources. For example, a mod might provide an entity model for an entity defined in the default mod in order to replace the default model with a more detailed one. To do this, the mod provides an entity model with the same name as the one it wants to replace. To resolve such name conflicts, TrenchBroom assigns priorities for mods, and if a name conflict occurs between different mods, the mod with the highest priority wins. Note that the default mod always has the lowest priority.

+

Materials and Material Collections

+

A material defines how a surface is rendered and how it interacts with light. In TrenchBroom, materials are usually closely related to textures. When TrenchBroom finds a texture on the filesystem, it automatically creates a default material for it. For Quake 3, additional material properties are read from shader files. Materials are usually not provided individually, but as material collections. A material collection can be a directory containing loose image files, or it can be an archive such as a wad file. Some games such as Quake 2 come with textures that are readily loadable by TrenchBroom. Such textures are called internal. External textures on the other hand are textures that you provide by loading a wad file. Since some games such as Quake don’t come with their own textures readily available, you have to obtain the textures you wish to use and add them to TrenchBroom manually by loading a wad file.

+

Multiple material collections may contain a material with the same name, resulting in a name conflict. Such a conflict is resolved by observing the order in which the material collections were loaded - the material that was loaded most recently wins the conflict. You cannot control the load order unless you are using wad files.

+

Startup

+

The first thing you will see when TrenchBroom starts is the welcome window. This window allows you to open one of your most recently edited maps, to create a new map or to browse your computer for an existing map you wish to open in TrenchBroom.

+
+ TrenchBroom’s welcome window (Mac OS X) +
+

You can click the button labeled “New map…” to create a new map or you can click the button labeled “Browse…” to find a map file on your computer. Double click one of the documents in the list on the right of the window to open it. The light gray text on the left gives you some information about which version of TrenchBroom you are currently running. The version information is useful if you wish to report a problem with the editor (see here for more information).

+

If you choose to create a new map, TrenchBroom needs to know which game the map should be for, and will show a dialog in which you can select a game and, if applicable, a map format. This dialog may also be shown when you open an existing map. TrenchBroom will try to detect this information from the map file, but if that fails, you need to select the game and map format.

+
+ The game selection dialog (Mac OS X) +
+

The list of supported games is shown on the right side of the dialog. Below the game list, there is a dropdown menu for choosing a map format; this is only shown if the game supports more than one map format. One example for this is Quake, which supports both the standard format and the Valve 220 format for map files. In the screenshot above, none of the games in the list were actually found on the hard disk. This is because the respective game paths have not been configured yet. TrenchBroom allows you to create maps for missing games, but you will not be able to see the entity models in the editor and other resources such as materials might be missing as well. To open the game configuration preferences, you can click the button labeled “Open preferences…”. Click here to find out how to configure the supported games.

+

Once you have selected a game and a map format, TrenchBroom will open the main editing window with a new map. The following section gives an overview of this window and its main elements. If you want to find out how to work with mods and how to add materials, you can skip ahead to the respective sections.

+

Main Window

+

The main window consists of a menu bar, a toolbar, the editing area, an inspector on the right and an info panel at the bottom. In the screenshot below, there are three editing areas: one 3D viewport and two orthographic 2D editing areas.

+
+ The main editing window (Ubuntu Linux) +
+

The sizes of the editing area, the inspector and the info bar can be changed by dragging the dividers with the mouse. This applies to some of the dividers in the inspector as well. If a divider is 2 pixels thick, it can be dragged with the mouse. The positions of the dividers and the size of the editing window are saved when you close a window. The following subsections introduce the most important parts of the main window: the editing area, the inspector, and the info bar. The toolbar and the menu will be explained in more detail in later sections.

+

The Editing Area

+

The editing area is divided in two sections: The context sensitive info bar at the top and the viewports below. The info bar contains different controls depending on which tool is currently activated. You can switch between tools such as the rotate tool and the vertex tool using the toolbar buttons, the menu or with the respective keyboard shortcuts. The context sensitive controls allow you to perform certain actions that are relevant to the current tool such as setting the rotation center when in the rotate tool or moving objects by a given delta when in the default move tool. Additionally, there is a button labeled “View Options” on the right of the info bar. Clicking on this button unfolds a dropdown containing controls to filter out certain objects in the viewports or to change how the viewport renders its contents.

+
+ The info bar with view dropdown (Windows 10) +
+

There are two types of viewports: 3D viewports and 2D viewports. TrenchBroom gives you some control over the layout of the viewports: You can have one, two, three, or four viewports. See section View Layout and Rendering to find out how to change the layout of the viewports. If you have fewer than four viewports, then one of the viewports can be cycled by hitting . Which of the viewports can be cycled and the order of cycling the viewports is given in the following table:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
No. of ViewportsCycling ViewCycling Order
1Single view3D > XY > XZ > YZ
2Right viewXY > XZ > YZ
3Bottom right viewXZ > YZ
4None
+

There are three types of 2D viewports: the XY, the XZ, and the YZ viewport. You can also think of these viewports as the top, the front, and the side view, respectively. The following table summarizes the properties of the three 2D viewports. Remember that Quake-based engines use a right handed coordinate system.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ViewportRight AxisUp AxisNormal AxisName
XY+X+Y+ZTop
XZ+X+Z-YFront
YZ+Y+Z+XSide
+

The normal axis is the axis that would be protruding from the screen when looking at the respective 2D viewport. In the case of the XY viewport, the normal axis is the positive Z axis, but in the case of the XZ viewport, the normal axis is the negative Y axis. For the mathematically inclined, the normal axis is the cross product of the right axis and the up axis. Sometimes, we will also refer to the inverted normal axis as the depth axis. So, the depth axis of the XY viewport is the negative Z axis. We also refer to the plane that is spanned by the first two axes as the view plane of a 2D viewport. Accordingly, the view plane of the XZ viewport is the X/Z plane.

+

The compass In the bottom left of each viewport, there is a compass that indicates the orientation of the camera of that viewport. In the 3D viewport, you can see how the compass rotates when you rotate the camera. In the 2D viewport, the compass axes are fixed, but they indicate which of the coordinate system axes are the right and the up axis for that viewport. The colors of the compass hands represent the axes: Red is the X axis, green is the Y axis, and blue is the Z axis (RGB vs. XYZ).

+

At most one of the viewports can have focus, that is, only one of them can receive mouse and keyboard events. Focus is indicated by a highlight rectangle at the border of the viewport. If no viewport is focused, you have to click on one of them to give it focus. Once a viewport has focus, the focus follows the mouse pointer, that is, to move focus from one viewport to another, simply move the mouse to the other viewport. The focused viewport can also be maximized by choosing from the menu. Hit the same keyboard shortcut again to restore the previous view layout.

+

Map Bounds

+
+ McKinley Base and Quake map bounds +
+

Game engines often impose a limit on the usable/playable volume of space. TrenchBroom can display this limit as a guide to use when creating your map. Such bounds will appear as an orange square or rectangle in the 2D viewports. For example, the image above shows the Quake map McKinley Base (ctf1 from Threewave CTF) within the normal bounds for a Quake map.

+

Map Properties (Ubuntu Linux) If bounds are configured for a game, they will usually represent the limits observed by the last official release or patch of a particular game engine. Those bounds may not be correct for your situation, so you can disable or modify the displayed bounds using the Map Properties portion of the Map Inspector, as shown here. (More about the Map Inspector in the next section below.)

+

In Quake-engine games, these bounds represent a limit on the volume that can contain players, items, or other entities. Static geometry (plain brushes) can extend further, which is why these limits are often called “soft bounds”. As far as TrenchBroom is concerned however, it is just drawing orange lines at whatever coordinates are indicated in the game configuration file… if this is a non-Quake-engine game then the bounds could represent something else.

+

In any case, keep in mind that the displayed bounds are just a guide that you should use to help yourself stay within the limits of your target game engine. Changing the bounds in TrenchBroom will not change the behavior in the game!

+

The Inspector

+

The inspector is located at the right of the main window and contains various controls, distributed to several pages, to change certain properties of the currently selected objects. You can show or hide the inspector by choosing . To switch directly to a particular inspector page, choose for the map inspector, for the entity inspector, and for the face inspector.

+
+ Map, Entity, and Face inspectors (Mac OS X) +
+

The Map Inspector allows you to edit layers, configure displayed map bounds, and set up which game modifications (mods) you are working with. The Entity Inspector is the tool of choice to change the properties of entities. It also contains an entity browser that allows you to create new entities by dragging them from the browser to a viewport and it allows you to set up entity definitions. Additionally, you can manage entity definition files in the entity inspector. The face inspector is used to edit the attributes of the currently selected faces. At the top, it has a graphical UV editor. Below that, you can edit the face attributes directly by editing their values. To select a material for the currently selected faces, you can use the material browser.

+

The Info Bar

+

You can show or hide the info bar by choosing . It contains the console where TrenchBroom prints out messages, warnings and errors, and the live issue browser where you can view, filter and resolve issues with your map.

+

Camera Navigation

+

Navigation in TrenchBroom is quite simple and straightforward. You will mostly use the mouse to move and pan the camera and to look around. There are also some keyboard shortcuts to help you position the camera with more precision. Just like in Quake, the camera cannot be rolled - in other words, up is always in the positive Z direction and down is always in the negative Z direction. The behavior of the camera can be controlled in the preferences.

+

Looking and Moving Around

+

In the 3D viewport, you can look around by holding the right mouse button and dragging the mouse around. There are several ways to move the camera around. First and foremost, you can move the camera forward and backward in the viewing direction by spinning the scroll wheel. If you prefer to have the scroll wheel move the camera in the direction where the mouse cursor is pointing, you can check the “Move camera towards cursor” option in the preferences. To move the camera sideways and up / down, hold the middle mouse button and drag the mouse in any direction. For tablet users, there is an option in the preferences that will enable you to move the camera horizontally by holding . Additionally, you can use the following keyboard shortcuts:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectionKey
Forward
Backward
Left
Right
Up
Down
+

To adjust the movement speed of the these keyboard shortcuts, you can either go the preferences and adjust the corresponding slider, or you can turn the mouse wheel while holding the right mouse button in the 3D view.

+

Orbiting

+

The camera orbit mode allows you to rotate the camera about a selectable point. To get an idea as to what this means, imagine that you define a point in the map by clicking on a brush. The point where you clicked will be the center of your camera orbit. Now image a sphere whose center is the point where you just clicked and whose radius is the distance between the camera and the point. Orbiting will move the camera on the surface of that sphere while adjusting the camera’s direction so that you keep looking at the same point. Visually, this is the same as rotating the entire map about the orbit center. Of course, you are not actually rotating anything - only the camera’s position and direction are modified. Note that, since up and down are always fixed, you cannot cross the north and south poles of the orbit sphere.

+

Camera orbit mode is very useful if you are editing a brush because it allows you to view this brush from all sides quickly. Its best to try it and see for yourself how useful it is. To invoke the orbit mode, click and drag with the right mouse button while holding . The orbit center is the point in the map which you initially clicked. Dragging sideways will orbit the camera horizontally and dragging up and down will orbit the camera vertically. You can change the orbit radius during the orbit with the scroll wheel.

+

Automatic Navigation

+

You can center the camera on the current selection by choosing from the menu. This will position the camera so that all selected objects become visible. The camera will not be rotated at all; only its position will be changed. Note that this action will also adjust the 2D viewports so that the selection becomes visible there as well.

+

Finally, you can move the camera to a particular position. To do this, choose and enter the position into the dialog that pops up. This does not affect the 2D views.

+ +
+ Linked YZ and XZ viewports +
+

Navigating the 2D viewports is naturally a lot simpler than navigating the 3D viewport. You can pan the viewport by holding and dragging either the middle or the right mouse button, and you can use the scroll wheel to adjust the zoom. Note that if you have set your viewport layout to show more than one 2D viewport, then the 2D viewports are linked. Specifically, the zoom factor is linked so that you always have a consistent zoom level across all 2D viewports, and the viewports are panned simultaneously along the same axes. This means that if you pan the XY viewport along the X axis, the XZ viewport gets panned along the X axis, too, so that you don’t have to pan both viewports manually. Also note that zooming always keeps the coordinates under the mouse pointer invariant, that is, you can focus on a particular object or area by hovering the mouse over it and zooming in or out.

+

FOV and Zoom

+

For the 3D view, the camera FOV (field of vision) can be adjusted in the view preferences by dragging the slider. This is a permanent setting.

+

To temporarily adjust the camera’s zoom, hold and scroll the mouse wheel. To reset the zoom factor, hit .

+

Selection

+

There are two different kinds of things that can be selected in TrenchBroom: objects and brush faces. Most of the time, you will select objects such as entities and brushes. Selecting individual brush faces is only useful for changing their attributes, e.g. the materials. You can only select objects or brush faces, but not both at the same time. However, a selection of brushes (and nothing else) is treated as if all of their brush faces were selected individually.

+
+ Object selection in 3D and 2D viewports +
+

In the 3D viewport, selected objects are rendered with red edges and slightly tinted faces to distinguish them visually. The bounding box of the selected objects is rendered in red, with spikes extending from every corner when the mouse hovers over one of the selected objects. These spikes are useful to precisely position objects in relation to other objects. Additionally, the dimensions of the bounding box are displayed in the 3D viewport. In a 2D viewport, selected objects are just rendered with red edges. No spikes or bounding boxes are displayed there since the 2D viewports have a continuous grid anyway.

+

Selecting Objects

+

To select a single object, simply left click it in a viewport. Left clicking anywhere in a viewport deselects all other selected objects, so if you wish to select multiple objects, hold while left clicking the objects to be selected. If you click an already selected object while holding , it will be deselected. You can also paint select multiple objects. First, select an object, then hold while dragging over unselected objects. Take care not to begin your dragging over a selected object, as this will duplicate the selected objects. Note that this even applies to occluded objects, so when you start your paint selection, you must ensure that no object under the mouse is selected.

+

In the 3D viewport, you can only select the frontmost object with the mouse. To select an object that is obstructed by another object, you can use the mouse wheel. First, select the frontmost object, that is, the object that occludes the object that you really wish to select. Then, hold and scroll up to push the selection away from the camera or scroll down to pull the selection towards the camera. Note that the selection depends on what object is under the mouse, so you need to make sure that the mouse cursor hovers over the object that you wish to select.

+
+ Selection drilling in the 3D viewport +
+

In a 2D viewport, you can also left click an object to select it. But unlike in the 3D viewport, this will not necessarily select the frontmost object. Instead, TrenchBroom will analyze the objects under the mouse, specifically the faces under the mouse, and it will find the one with the smallest visible area. Having found such a face, it will select the object to which this face belongs. Since entities don’t necessarily have faces, the faces of their bounding boxes will be considered instead. The advantage of this technique is that it allows you to easily select occluded objects in the 2D viewports.

+

You may also think of left click selection like this: In both the 3D viewport or a 2D viewport, TrenchBroom first compiles a set of candidate objects. These are all objects under the mouse. Then, it must choose an object to be selected from these candidates. In the 3D viewport, the frontmost object always wins (unless you’re using the scroll wheel to drill the selection), and in a 2D view, the object with the smallest visible area wins. Other than that, selection behaves exactly the same in both viewports, that is, you can hold to select multiple objects and so on.

+

Sometimes, selecting objects manually is too tedious. To select all currently editable objects, you can choose from the menu. Note that hidden and locked objects are excluded, so this command is particularly useful in conjunction with those features. Another option to select multiple objects at once is to use selection brushes. Just create one or more new brushes that enclose or touch all the objects you wish to select. These brushes are called selection brushes. Select all of these newly created selection brushes, and choose to select every object touched by the selection brushes, or choose to select every object enclosed inside them. Note that selection brushes will disappear after they were made use of.

+
+ Using a selection brush +
+

A similar operation can be found under , but this particular operation is only available when a 2D view has focus. It projects the selection brushes onto the view plane of the currently focused 2D viewport, which results in a 2D polygon, and then selects every object that is contained entirely within that polygon. You can think of this as a cheap lasso selection tool that works like , but without having to adjust the distance and thickness of the selection brushes.

+

If you have selected a single brush that belongs to an entity or group, and you wish to select every other object belonging to that entity or group, you can choose . The same effect can be achieved by left double clicking on a brush that belongs to an entity or group. The menu command is useful for diagnostic purposes. If an external program such as a map compiler presents you with an error message and a line number indicating where in the map file that error occurred, you can use this menu command to have TrenchBroom select the offending object for you.

+

Choose from the menu to invert the selection, i.e. select everything that is currently unselected (excluding hidden and locked objects).

+

Finally, you can deselect everything by left clicking in the void, or by choosing .

+

Selecting Brush Faces

+
+ Selected brush face +
+

To select a brush face, you need to hold and left click it in the 3D viewport. You can select multiple brush faces by additionally holding . To select all faces of a brush, you can left double click that brush while holding . If you additionally hold , the faces are added to the current selection. To paint select brush faces, first select one brush face, then left drag while holding and . To deselect all brush faces, simply click in the void or choose .

+

Editing

+

In this section, we will cover all topics related to the actual editing of a map. We begin by explaining how to set up the map itself, that is, how to set up mods, entity definitions, and material collection. Afterwards, we show you how to create new objects such as entities or brushes, how to edit and transform them, and how to delete them. After that, we explain how you can work with materials in TrenchBroom. The following section introduces the various tools at your disposal to shape brushes while the section after that focuses on entities and how to edit their properties. The goal of the final section is to help you keep an overview in your map by using layers, groups, and by various other means.

+

Map Setup

+

The first step when creating a new map is the setup of mods, entity definitions, and material collections.

+

Setting Up Mods

+

Mod editor We explained previously that a mod is just a sub directory in the game directory itself. Every game has a default mod that is always active and that cannot be deactivated - in Quake, this is id1, the directory that contains all game resources. TrenchBroom supports an unlimited number of additional mods. Mods can be added, removed, and reordered by using the mod editor, which you can find at the bottom of the map inspector.

+

When the editor starts, the mod editor is folded, but you can unfold it by clicking on its title bar. You are then presented with a two column view of the available mods (left column) and the enabled mods (right column). The list of available mods contains every sub directory in the game directory in alphabetic order. This list can be filtered using the search field at the bottom. To enable some mods, select them in the list of available mods and click on the plus icon below the list of enabled mods. To disable mods, select them in the list of enabled mods and click on the minus icon.

+

The order of the enabled mods is important because it defines the priorities for loading resources. You can change the priority of enabled mods by reordering them in the list. For this, you can select an enabled mod and use the small triangles below the list of enabled mods to push it up or down.

+

Mods are stored in a worldspawn property called "_tb_mod".

+

Loading Entity Definitions

+

Entity definition editor Entity definitions are text files containing information about the meaning of entities and their properties. Depending on the game and mod you are mapping for, you might want to load different entity definitions into the editor. To load an entity definition file into TrenchBroom, switch to the entity inspector and click on the entity browser title bar where it says “Settings”. The entity definition browser is horizontally divided into two areas. The upper area contains a list of builtin entity definition files. These are the entity definition files that came with TrenchBroom for the game you are currently working on. You can select one of these builtin files by clicking on it. TrenchBroom will load the file and update its resources accordingly. Alternatively, you may want to load an external entity definition file of your own. To do this, click the button labeled “Browse” in the lower area of the entity definition browser and choose the file you wish to load. Currently, TrenchBroom supports Radiant DEF files and ENT files as well as Valve FGD files. To reload the entity definitions (as well as the referenced models) from the currently loaded external file, you can click the button labeled “Reload” at the bottom or use . This may be useful if you’re editing an entity definition file for a mod you’re working on.

+

Return to the entity browser by clicking on the entity browser title bar again where it says “Browser”.

+

Note that FGD and ENT files contain much more information than DEF files and are generally preferable. While TrenchBroom supports all of these file types, its support for FGD and for ENT is better and more comprehensive. Unfortunately, DEF files are still relevant because Radiant style editors require them, so TrenchBroom allows you to use them, too.

+

The path of an external entity definition file is stored in a worldspawn property called "_tb_def".

+

Managing Materials

+

Wad Files

+

Wad files are managed via the wad worldspawn property. The property contains a semicolon separated list of paths where TrenchBroom will load a wad file from. Map compilers also use this property to find wad files.

+

Smart wad editor In TrenchBroom, you cannot edit this property directly, so you must use a smart property editor that’s available for the wad property. This smart editor is available when you select the wad worldspawn property in the entity property editor. Click the + icon to add a wad file or the - icon to remove the selected wad files. The two triangle icons move a selected wad file up and down in the list. This only has an effect on how name conflicts between materials are resolved. The icon with the two circular arrows reloads all texture wads.

+

Alternatively, you can drag wad files onto the editor window from a file browser such as the Windows explorer. If the map uses wad files, these files will be loaded and their paths will get appended to the wad worldspawn property.

+

Materials from directories

+

Unless you are using wad files, you don’t need to do anything to manage your materials - TrenchBroom will automatically load all available material collections.

+

If you want to provide your own custom textures, you need to put them in a subdirectory where TrenchBroom can find them. For Quake 2, this means that you need to create a subdirectory called textures in the directory of the mod you’re mapping for, or in the baseq2 directory. Then you need to create another subdirectory with a name of your choice. Then you copy your texture files into that directory. TrenchBroom will then find that directory (possibly after restarting the editor) and allow you to load the textures from there. Currently, for a generic game you must create a textures folder in the game path directory you set in game configuration, or in a directory you loaded as a mod.

+

You need to place your textures in a subdirectory exactly one level deep in the textures folder. Any loose images in textures will not be detected, nor will any nested in subdirectories of your collection.

+

Interacting with the Editor

+

Before we delve into specific editing operations such as creating new objects, you should learn some basics about how to interact with the editor itself. In particular, it is important to understand the concept of tools in TrenchBroom and how mouse input is mapped to 3D coordinates.

+

Working with Tools

+

All editing functionality in TrenchBroom is provided by tools. There are two types of tools in TrenchBroom: Permanently active tools and modal tools. Modal tools are tools which have to be activated or deactivated manually by the user. Permanently active tools are tools which are always available, unless they are deactivated by a modal tool. The following table lists all tools with a short description:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ToolViewportsTypePurpose
Camera Tool2D, 3DPermanentAdjusting the 3D camera and the 2D viewports
Selection Tool2D, 3DPermanentSelecting objects and brush faces
Simple Shape Tool2D, 3DPermanent*Creating simple shapes
Complex Shape Tool3DModalCreating arbitrarily shaped brushes
Entity Drag Tool2D, 3DPermanentCreating entities by drag and drop
Resize Tool2D, 3DPermanent*Resizing brushes by dragging faces
Move Tool2D, 3DPermanent*Moving objects around
Rotate Tool2D, 3DModalRotating objects
Scale Tool2D, 3DModalScaling brushes
Shear Tool2D, 3DModalShearing brushes
Clip Tool2D, 3DModalClipping brushes
Vertex Tool2D, 3DModalEditing brush vertices, edges, and faces
+

Tools of the type Permanent* are deactivated whenever a modal tool is active. For example you cannot create cuboid brushes when the vertex tool is active. Additionally, at most one modal tool can be active at a time. You can activate and deactivate modal tools using the menu and keyboard shortcuts listed in the following table:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ToolMenu
Complex Shape Tool
Rotate Tool
Scale Tool
Shear Tool
Clip Tool
Vertex Tool
+

Tool buttons Additionally, tools can be toggled by using the buttons on the left of the toolbar. In the image, the first button is active, however, this particular button does not represent any of the modal tools listed in the table above. Rather, it indicates that no modal tool is currently active, and therefore all permanent tools are available. The buttons icon indicates that objects can be moved, which is only possible if no modal tool is active. The second button represents the convex brush tool, the third button toggles the clip tool, the fourth button is used to toggle the vertex tool and the fifth button toggles the rotate tool.

+

You can learn more about these tools in later sections. But before you can learn about the tools in detail, you should understand how TrenchBroom processes mouse input, which is what the following two sections will explain.

+

Canceling Operations and Tools

+

To cancel a mouse drag, hit . The operation will be undone immediately. The same keyboard shortcut can be used to cancel all kinds of things in the editor. The following table lists the effects of canceling depending on the current state of the editor.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
StateEffect
Complex Shape ToolDiscard all placed points; deactivate tool
Clip ToolDiscard most recently placed clip point; deactivate tool
Vertex ToolDiscard current vertex selection; deactivate tool
Selection ToolDiscard current selection
+

For those tools where a second effect is listed (separated by a semicolon), the second effect only takes place if the first effect couldn’t be realized. For example, if the clip tool is active but no clip points have been placed, then hitting will deactivate the clip tool. Hitting yet again will deselect all selected objects or brush faces.

+

In addition, you can hit to directly deactivate the current tool regardless of what state the tool is in.

+

Mouse Input in 3D

+

It is very important that you understand how mouse input is mapped to 3D coordinates when editing objects in TrenchBroom’s 3D viewport. Since the mouse is a 2D input device, you cannot directly control all three dimensions when you edit objects with the mouse. For example, if you want to move a brush around, you can only move it in two directions by dragging it. Because of this, TrenchBroom maps mouse input to the horizontal XY plane. This means that you can only move things around horizontally by default. To move an object vertically, you need to hold during editing. This applies to moving objects and vertices, for the most part.

+

But this is not always true, since some editing operations are spatially restricted. For example, when resizing a brush, you drag one of its faces along its normal, so the editing operation is restricted to that normal vector. In fact, the mouse pointer’s position must be mapped to a one-dimensional value that represents the distance by which the brush face has been dragged. Whenever mouse input has to be mapped to one or two dimensions, TrenchBroom does this mapping automatically and no additional thought is required. But if mouse input must be mapped to three dimensions, TrenchBroom does so by employing the editing plane metaphor explained before.

+

Mouse Input in 2D

+

Mapping mouse input to 3D coordinates is much simpler in the 2D viewports, because the first and second dimension is given by the fixed viewport axes, and the third dimension (the depth) is usually taken from the context of the editing operation. For example, if you move an object by left dragging it in the XY viewport, then the mouse input is mapped to the X and Y axes, and the object’s Z coordinates remain unchanged. When creating new objects, the depth is usually computed from the bounds of the most recently selected objects. So if you create a new brush by left dragging in the XY view, its distance and its height is determined by the most recently selected objects, while its X/Y extents are determined by the mouse drag.

+

Axis Restriction

+

To avoid imprecise movements when moving objects in two dimensions, you can limit movement to a single axis when using the mouse. By default, objects are moved on the XY plane in the 3D viewport or on the view plane in the 2D viewports. To move objects vertically in the 3D viewport, you have to hold . This works either when you start moving the objects and also during a drag. Furthermore, when moving objects on the XY plane in the 3D viewport or on the view plane in the 2D viewports, you can restrict the movement to one axis by holding . TrenchBroom will then restrict movement to the axis on which the objects have moved the farthest. So if you are moving objects in the 3D viewport and you want to restrict movement to the X axis, move the objects some distance along the X axis and press to lock all movement to that axis. When you release , the restriction is lifted again and the objects will move to the position under the mouse. This applies not only to moving objects, but also moving vertices in the vertex tool and moving clip points in the clip tool. In the clip tool, the axis restriction only works in the 2D viewports however.

+
+ Moving a brush in the 3D viewport with trace line +
+

Note that TrenchBroom draws a trace line for you when you move objects with the mouse. The trace line helps to move objects in straight lines and as a visual feedback for your move. When an axis restriction is active, the trace line is rendered thicker.

+

The Grid

+

TrenchBroom provides you with a static grid to align your objects to each other. The grid size can be 1, 2, 4, 8, 16, etc. up to 256. It is also possible to set the grid size to a value smaller than 1, more precisely to 0.5, 0.25 or 0.125. If grid snapping is enabled, then most editing operations will be snapped to the grid. For example, you can only move objects by the current grid size if grid snapping is enabled. In the 3D viewport, the grid is projected onto the brush faces. Therefore the grid may appear distorted if a brush face is not axis aligned. In the 2D viewports, the grid is just drawn in the background. You can change the brightness of the grid lines in the preferences.

+

The grid size can be set via the menu, or by scrolling the mouse wheel while holding both and .

+

Map View Context Menu

+

Right clicking in a map view gives the following context menu:

+
+
Group
+
Groups the selected objects. +
+
Ungroup
+
Ungroups the selected objects. +
+
Merge groups
+
When multiple groups are selected, merges them into a single group. +
+
Rename Groups
+
Rename the selected groups. +
+
Move to Layer
+
Move the selected objects to the chosen layer. +
+
Make Layer LAYERNAME Active
+
Changes the current layer to the chosen layer. +
+
Hide Layers
+
Hide all layers which contain selected objects. +
+
Isolate Layers
+
Isolate the layers containing selected objects. +
+
Select All in Layers
+
Select all objects in the layers which contain the selected objects. +
+
Make Structural
+
Moves brushes back into the world and clears any content flags. See Brush Entities. +
+
Reveal MATERIALNAME in Material Browser
+
Switches to the face inspector and scroll to the clicked material in the Material Browser. +
+
Create Point Entity
+
Create a Point Entity of the chosen type. +
+
Create Brush Entity
+
Create a Brush Entity with the selected brushes. +
+
+

Creating Objects

+

TrenchBroom gives you various options on how to create new objects. In the following sections, we will introduce these options one by one.

+

Creating Simple Shapes

+

The easiest way to create a new brush is to just draw it out with the mouse using the Simple Shape Tool. The tool is enabled by default when nothing else is selected or any other tool active. Left drag in the 3D viewport or any of the 2D viewports.

+

When drawing a brush in the 3D viewport, its shape is controlled from the point under the mouse where you initially started your drag, to the point currently under the mouse cursor, and the current grid size. When drawing your brush on the XY axes, the height of the brush will be set to the current grid size. While dragging you can force X and Y axes to be equal by holding , or force X, Y and Z axes to be equal by holding +, and its also possible to change just the height while drawing a brush by holding .

+
+ Creating a cuboid in the 3D viewport +
+

When drawing a brush in a 2D viewport, you only control its extents on whatever axes the 2D view is set to display. So if you are drawing a brush in the XZ view, you control the X/Z extents with the mouse, and there’s no way to change the Y extents directly, which is always fixed to the Y extents of the most recently selected objects. This of course applies to all of the different 2D viewports in the same way.

+

In either case, the material assigned to the newly created brush is the current material. The current material is set by choosing a material in the material browser or by selecting a face that already has a material. This concept applies to other ways of creating new brushes, too.

+

This way of creating brushes only allows you to the simple shapes listed in the following table. In the next section, you will learn how to create more complex brush shapes with the complex shape tool.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ShapeDescription
CuboidCreates a cuboid shape
CylinderCreates a cylinder with a variable number of sides; potentially hollow
ConeCreates a cone with a variable number of sides
Spheroid (UV)Creates a spheroid shape made up of triangles and quads with two poles
Spheroid (Icosahedron)Creates a spheroid shape made up of triangles, based on an icosahedron
+

Note that the cylinder, cone and UV sphere shapes all have similar options, namely the number of sides and a circle mode. By using the same values for these options across different shapes, TrenchBroom will create shapes that fit onto each other perfectly.

+

There are three circle modes that can be selected via the corresponding buttons:

+ + + + + + + + + + + + + + + + + + + + + +
ModeDescription
Creates a circle with 4 edges aligned to the bounding box
Creates a circle with 4 vertices aligned to the bounding box
Creates a scalable circle
+

The last shape requires some explanation. It is not a perfect circle, rather, its vertices are slightly displaced so as to be perfectly aligned on the grid. Consider the following example.

+
+ A scalable hollow cylinder +
+

This hollow cylinder is scalable because its vertices are all aligned on the grid. Scaling it larger or smaller will keep the vertices neatly on an integer grid, and this can be beneficial for Quake-like map compilers because they usually handle geometry better when it is aligned on the grid. Scalable shapes can only have 12, 24, 48 or 96 sides. These types of curves are also called CZG curves.

+
+ Asymmetric scalable cylinder +
+

If you create an asymmetric scalable shape, it will not be scaled to fit the bounding box drawn with the mouse like the other shapes. Rather, only the middle portion of it will be elongated so that the vertices remain on the grid. This even applies to cones and UV spheres so that the different shapes still fit together.

+

Creating Complex Shapes

+

Drawing a rectangle and duplicating it If you want to create a brush that is not a simple, axis-aligned cuboid, you can use the brush tool. The brush tool allows you to define a set of points and create the convex hull of these points. A convex hull is the smallest convex volume that contains all the points. The points become the vertices of the new brush, unless they are placed within the brush, in which case they are discarded. Accordingly, the brush tool gives you several ways to place points, but there are two limitations: First, you can only place points in the 3D viewport, and second, you can only place points by using other brushes as reference.

+

To use the brush tool, you first have to activate it by choosing . Then, you can place single points onto the grid by left clicking on the faces of other brushes. Additionally, you can left double click on a face to place points on all of its vertices. You can also draw a rectangular shape by left dragging on an existing brush face and thereby place four points at the corners of that rectangle. Finally, if the points you have placed so far form a polygon, you can duplicate and move that polygon along its normal by left dragging it while holding . Once you have placed all points, hit to actually create the brush.

+

It is not possible to modify or remove points after they have been placed, except discarding all of them by hitting the key.

+

Creating Entities

+

There are two types of entities: point entities and brush entities, and it depends on the type how an entity is created. In the following sections, we present three ways of creating point entities and two ways to create brush entities.

+

Point Entities

+

There are three ways of creating new point entities. Firstly, you can drop new entities in the 3D and 2D viewports by using the map view context menu. To open the context menu, right click into the viewport. To create a point entity such as a pickup weapon or a monster, open the “Create Point Entity” sub menu and select the correct entity definition from the sub menus.

+
+ Dropping an entity with the context menu (Mac OS X) +
+

The location of the newly created entity depends on whether you clicked on the 3D viewport or a 2D viewport. If you clicked on the 3D viewport, then the entity will be placed on the brush under the mouse. If there was no brush under the mouse, then the entity will be placed at a default distance. Note that the bounding box of the entity will be snapped to the grid. If you clicked on the 2D view, then the position of the entity depends on what was under the mouse when you clicked, too. If a selected brush was under the mouse, then the new entity will be placed on that brush. If no selected brush was under the mouse, then the entity will be placed at the far end of the bounding box of the most recently selected objects. Again, the bounding box of the newly created entity will be snapped to the grid.

+

Entity browser Secondly, you can create new point entities by dragging them from the entity browser. The entity browser can be found in the entity inspector page. At the bottom of the entity browser, you can find a number of controls to change the sort order and to filter the entities displayed in the browser.

+

The leftmost dropdown list allows you to change the sort order. Entities can be sorted by name or by their usage count, with the most used entities at the top. The “Group” button toggles grouping the entities by their category, which is derived from the first part of the entity name. For example, all entities starting with “key_” are put into a category called “key”. The button labeled “Used” toggles all unused entities, when it is pressed, only those entities which are used in the map are shown in the browser. To filter entities by name, enter some text in the search box on the right. Only entities containing the search text will be shown in the browser.

+

To create a new entity, simply drag it out of the browser and onto the 3D or a 2D viewport. If you drag it onto the 3D viewport, the entity will be positioned on the brush under the mouse, with its bounding box snapped to the grid. If you drag the entity onto a 2D viewport, its position is determined by the far end of the most recently selected object.

+

Finally, you can create specific entities by assigning a keyboard shortcut in the preferences. This is useful for entities that are used very often such as lights. The entity will be created under the mouse cursor; its position will be computed in the same way as if the context menu was used.

+

Brush Entities

+

Moving brushes to brush entities Creating brush entities is also done using the context menu. Select a couple of brushes and right click on them, then select the desired brush entity from the menu. To move brushes from one brush entity to another, select the brushes you wish to move and right click on a brush belonging to the brush entity to which you want to move the brushes, and select “Move brushes to Entity ENTITY”, where “ENTITY” is the name of the target brush entity, for example “func_door” in the picture on the left. If the brush entity containing the brushes to be moved becomes empty, it will be automatically deleted. To move brushes from a brush entity back into the world and clear content flags, select the brushes, right click and select “Make Structural”.

+

Additionally, you can also assign a keyboard shortcut to create a specific brush entity in the preferences.

+

Often, it is much quicker to create new objects by duplicating existing ones. Objects can be duplicated using dedicated functions in TrenchBroom, or just by copying and pasting them.

+

Duplicating Objects

+

The currently selected objects can be duplicated by choosing . This will duplicate the objects in place, that is, the duplicates retain the exact position of the original objects. To give visual feedback, the duplicated objects are flashed in white really quickly. In the following short clip, you can see that the selected brush gets duplicated. After that, the duplicated brush is moved upwards.

+
+ Duplicating a brush in place +
+

Very often, you will want to duplicate objects and move them to a different position immediately afterwards, because having duplicates retain the same position as their originals is very seldom useful. That’s why you can also duplicate and move objects at once without having to perform two separate actions. To duplicate and move objects, you can use the following keyboard shortcuts:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectionShortcut (2D)Shortcut (3D)
Left
Right
Up
Down
Forward
Backward
+

Essentially, these are the same keyboard shortcuts that you use to move objects around in the 3D and 2D viewports, but while holding . In the same vein, you can hold while left dragging a selected object to duplicate and move all selected objects.

+
+ Duplicating and moving a brush +
+

Note that in the image above, the selected brush flashes while it is moved to the right. This indicates that in this case, the duplication and the translation happened at the same time instead of one after the other as in the previous example.

+

Copy and Paste

+

You can copy objects by selecting them and choosing . TrenchBroom will create text representations of the selected objects as if they were saved to a map, and put that text representation on the clipboard. This allows you to paste them into map files, and also to directly copy objects from map files and paste them into TrenchBroom. Note that you can also copy brush faces, which will also put a text representation of that brush face on the clipboard. Having copied a brush face, you can paste the attributes of that face (material, offset, scale, etc.) into other selected brush faces.

+

There are two menu commands to paste objects from the clipboard into the map. The simpler of the two is , which will simply paste the objects from the clipboard without changing their position. The other command, available at , does not paste the objects from the clipboard at their original positions, but will try to position them using the current mouse position. If pasted into the 3D viewport, the pasted objects will be placed on top of the brush under the mouse. If no brush is under the mouse, the objects will be placed at a default distance. The bounding box of the pasted objects is snapped to the grid, and TrenchBroom will attempt to keep the center of the bounding box of the pasted objects near the mouse cursor. The following clip illustrates these concepts. The light fixture is copied, then pasted several times.

+
+ Pasting objects in the 3D viewport +
+

Positioning of objects pasted into a 2D viewport attempts to achieve a similar effect by positioning the pasted objects such that they line up with the far end of the bounds of the most recently selected objects while keeping them under the mouse, with their center snapped to the grid.

+

Editing Objects

+

The following section is divided into several sub sections: First, we introduce editing operations that can be applied to all objects, such as moving, rotating, or deleting them. Then we proceed with the tools to shape brushes, such as the clip tool, the vertex tool, and the CSG operations. Afterwards we explain how you work with materials in TrenchBroom, and then we move on to editing entities and their properties. The final subsection deals with TrenchBroom’s undo and redo capabilities.

+

Moving Objects

+

You can move objects around by using either the mouse or keyboard shortcuts. Left click and drag on a selected object to move it (and all other selected objects) around. In the 3D viewport, the objects are moved on the XY plane by default. Hold to move the objects vertically along the Z axis. In a 2D viewport, the objects are moved on the viewport’s view plane. There is no way to change an object’s distance from the camera using the mouse in a 2D viewport. If grid snapping is enabled, the distances by which you move them are snapped to the grid component-wise, that is, if the grid is set to 16 units, you can move objects by 16 units in either direction.

+

You can also use the keyboard to move objects. Every time you hit one of the shortcuts in the following table, the object will move in the appropriate direction by the current grid size. Also remember that you can duplicate objects and move them in the given direction in one operation by holding and hitting one of the keyboard shortcuts listed below.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectionShortcut (2D)Shortcut (3D)
Left
Right
Up
Down
Forward
Backward
+

Note that the meaning of the keyboard shortcuts depends on the viewport in which you use them. While moves the selected objects in the direction of the up axis if used in a 2D viewport, it moves the objects (roughly) in the direction of the camera viewing direction (i.e. forward) on the editing plane if used in the 3D viewport. Likewise, moves the selected objects in the direction of the normal axis (i.e. forward) if used in a 2D viewport and in the direction of the negative Z axis if used in the 3D viewport.

+
+ Moving objects +
+

To move objects by a specified offset, select to bring up a window where you can enter a vector. Click “OK” and the currently selected objects will be moved by that vector.

+

Rotating Objects

+

The easiest way to rotate objects in TrenchBroom is to use the following keyboard shortcuts:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ShortcutTypeRotation (3D)Rotation (2D)
RollClockwise about view axisClockwise about normal axis
RollCounter-clockwise about view axisCounter-clockwise about normal axis
PitchClockwise about right axisClockwise about right axis
PitchCounter-Clockwise about right axisCounter-Clockwise about right axis
YawClockwise about Z axisClockwise about up axis
YawCounter-clockwise about Z axisCounter-clockwise about up axis
+

If the rotate tool is active, these keyboard shortcuts rotate the selected objects using the center of rotation and the angle set using the tool’s rotation handle and the input controls above the viewports. If the rotate tool is not active, the center of rotation is the center of the bounding box of the currently selected objects (snapped to the grid), and the rotation angle is fixed to 90°.

+

3D rotation handle The rotate tool gives you more control over rotation than the keyboard shortcuts do. Hit to activate the rotate tool and a rotation handle will appear in the viewports. The rotation handle allows you to set the center of rotation and to perform the actual rotation of the selected objects about the X, Y, or Z axis. In the 3D viewport, you can rotate the objects about any of those axes by left dragging the appropriate part of the rotate handle, but in a 2D viewport, you can only rotate the objects about the normal axis of that viewport. The angle of rotation defaults to 15 degrees, but it can be changed in the controls that appear above the editing views when you activate the rotate tool. During rotation, the current angle of rotation is shown at the center of the rotation handle.

+

In the 3D viewport, the rotation handle will appear as in the image on the left. It has three axes, color coded with the X axis in red, the Y axis in green, and the Z axis in blue as usual. In addition to the axes, it has three quarter circles, again color coded, and one small spherical handle at the center. The center handle (the yellow sphere) changes the center of rotation if you drag it with the left mouse button. Moving the center of rotation works exactly as moving objects with the move tool does. If you hover the mouse over the center handle, you will notice that the coordinates of the center of rotation are displayed above the center handle and that the handle is highlighted by a red outline. To perform a rotation, you have to drag one of the three color coded quarter circles. When you hover over one of them, it will be highlighted to indicate that you can start dragging. Clicking and dragging the blue quarter circle with the left mouse button rotates the objects about the Z axis, and likewise for the red and green handles (see the clip below).

+

2D rotation handle In the 2D viewport, the rotation handle will just appear as a circle with one smaller circular handle at the center. The center handle allows you to move the center of rotation on the view plane of that viewport, and the outer circle allows you to perform the rotation. In the 2D viewports, the handle is also color coded, the colors of the outer circle reflecting the axis of rotation in a similar fashion to the 3D rotate handle. To start a rotation, drag the outer circle in a circular fashion. As in the 3D view, the angle of rotation will be snapped to whatever value is entered in the angle control above the editing views, and during rotation the angle will be indicated at the center of the rotation handle.

+
+ Rotate tool controls +
+

Like the move tool, the rotate tool places some controls above the viewport. On the very left, there is a combo box that displays the coordinates of the center of rotation. This combo box automatically updates if you move the rotate handle around in the 2D or 3D viewports. If you want to set the center of rotation manually, you can enter three coordinates here and hit . Alternatively, you can click the button labeled “Reset” to set the center of rotation to the center of the bounding box of the currently selected objects, snapped to the grid. Finally, you can use the combo box to return the center of rotation to a previously used value. The rest of the controls allow you to perform a rotation by entering an angle in the text box, selecting the rotation axis from the dropdown list, and clicking the “Apply” button.

+
+ Rotating objects about the Z axis in the 3D viewport +
+

If you look closely at the clip above, you will notice that the entity in the picture, a green armor, rotates nicely with the brush it is placed on. Firstly, its position does not seem to change in relation to the brush, and secondly, its angle of rotation is also changed according to the rotation being performed by the user. Whether and how TrenchBroom can adapt the angle of rotation of an entity depends on the following rules.

+
    +
  • “angles” is interpreted as “pitch yaw roll” (if the entity model is a Quake MDL, pitch is inverted)
  • +
  • “mangle” is interpreted as “yaw pitch roll” if the entity classnames begins with “light”, otherwise it’s a synonym for “angles”
  • +
  • “angle” is interpreted as the rotation angle about the Z axis
  • +
  • If the point entity’s bounding box is not centered in the XY plane (e.g. Quake’s misc_explobox), attempts to rotate the entity in TrenchBroom will be blocked. This is done to prevent the model from being rotated out of the collision box, which doesn’t rotate in Quake.
  • +
+

Finally, if TrenchBroom has found a property that contains the rotation angle of the entity, it adapts the value of that property according to the rotation being performed by the user. These rules are quite complicated because sadly, the entity definitions do not contain information about how rotations should be applied to entities. But in practice, they should just perform as expected when you work with the rotate tool in the editor.

+
+ Checkbox +
+

This behavior can be disabled temporarily by toggling the checkbox to the right of the “Apply” button when the rotate tool is active. If the checkmark is removed, TrenchBroom will not update any entity properties except for the origin when an entity is rotated either by the rotate tool or by a shortcut.

+

Flipping Objects

+

Flipping has the effect of mirroring the selected objects, the mirror being a plane which is defined by the center of the bounding box of the selected objects, snapped to the grid, and by a normal vector. The normal vector of the plane depends on the actual flipping command and the viewing direction of the camera in the 3D viewport or the view plane of the focused 2D viewport. The following table explains how the normal vector is derived from this information.

+ + + + + + + + + + + + + + + + + + + + + + + +
ShortcutDirectionNormal (2D)Normal (3D)
HorizontalRight axisAxis-aligned right axis
VerticalUp axisZ axis
+

In the case of the 3D viewport, the normal of the mirror plane is the coordinate system axis that is closest to the right axis of the camera. This means that if the camera is pointing in the general direction of the Y axis, and therefore its right axis points in the general direction of the X axis, the normal of the mirror plane will be the X axis. Sometimes, you will not be able to determine which of the coordinate system axes is closest to the right axis of the camera because the right axis is close to two coordinate system axes. To avoid such confusion, it is best to perform flipping in the 2D viewports.

+

Scaling Objects

+

Hit to activate the scale tool. If you know the exact X/Y/Z scale factors you want, you can enter them in the toolbar and click “Apply”. The selected objects will be scaled relative to the center of their bounding box.

+
+ Scale Tool Toolbar +
+

Otherwise, there are various ways to interactively scale your selected objects.

+

In the 3D view:

+
    +
  • Dragging a side of the bounding box stretches that axis only.

    +
    + Dragging a side of the bounding box +
  • +
  • Dragging an edge stretches the two adjacent sides of the bounding box proportionally.

    +
    + Dragging an edge of the bounding box +
  • +
  • Dragging a corner resizes all 3 axes proportionally.

    +
    + Dragging a corner of the bounding box +
  • +
+

In 2D views:

+
    +
  • Corners allow unconstrained scaling along 2 axes.
  • +
  • Sides stretch a single axis only, as in the 3D view.
  • +
+

Two modifiers can be used in both the 2D and 3D views:

+
    +
  • Hold to scale all three axes to scale proportionally in 3D views, or only the two axes perpendicular to the camera in 2D views. You can press/unpress during a drag. ( has no effect when dragging corners in 3D, since all 3 axes are already scaled proportionally.)

  • +
  • Hold to move the scale anchor point to the center of the bounding box. Otherwise, the anchor point is opposite the handle being dragged.

    +
    + Dragging a side of the bounding box +
  • +
+

Shearing Objects

+

Hit to activate the shear tool. Dragging a side of the bounding box shears along that plane. You can add the key to drag vertically if you’re not shearing the top or bottom of the bounding box.

+

Alignment lock in the Shear tool only works in Valve 220 format maps.

+
+ Vertical shearing in the 3D viewport +
+

Deleting Objects

+

Deleting objects is as simple as selecting them and choosing . Note that if you delete all remaining brushes of a brush entity, that entity gets deleted automatically. Likewise, if you delete all remaining objects of a group, that group also gets deleted.

+

Shaping Brushes

+

TrenchBroom offers several tools to change the shapes of brushes. The most powerful of these tools, and also the one that requires the most care, is the vertex tool. Before we discuss this tool, we will introduce the clip tool with which you can chop parts off of brushes. But first, we introduce the extrude tool which, as the name suggests, allows you to quickly change the size of brushes. Finally, we explain how you can shape brushes using TrenchBroom’s CSG operations.

+

Extrusion

+

Brushes can be extruded using the extrude tool by moving their faces along their respective normal vectors with the mouse. To extrude a selected brush, hold and move your mouse pointer onto or near the face you wish to move. You will notice that one of the brush’s faces is highlighted with a yellow outline. Drag with your left mouse button while still holding to move the highlighted face along its normal. Note that you can also move brush faces which are behind the brush as long as these faces have an edge that is visible from the camera.

+
+ Extruding a brush in the 3D viewport +
+

Note that you cannot change the number of faces of a brush by with the extrude tool. This means that you cannot push a face back into a brush indefinitely. TrenchBroom will refuse to move it further as soon as that movement would make other faces disappear. The same applies to pulling a face out of a brush, which can make that face disappear. This is disallowed as well.

+

If you hold when you start dragging, the brush will not be extruded. Instead, a new brush will be created. Both of the original and the new brush together will have the same shape that the original would have had if you had just extruded it without holding , and the two brushes are split where the face you were dragging originally sat.

+
+ Splitting a brush in the 3D viewport +
+

When starting a drag with you can also drag inward to split the original brush:

+
+ Splitting a brush inward in the 3D viewport +
+

You can also extrude several brushes at the same time by moving their faces using the extrude tool, but only if these faces line up perfectly. As the following animation illustrates, it’s not enough that the faces are parallel - they have to be identical.

+
+ Extruding multiple brushes +
+

The extrude tool also works in the 2D viewports, of course, but the ability to move faces which are behind the selected brush is absent there. In both cases, TrenchBroom uses two methods to determine how to snap the distance by which you drag the face:

+
    +
  • The distance is snapped to the current grid size, i.e., if you drag a face by 17.5 units along its normal, it will be moved by 16.0 units if the current grid size is 16. This is useful if you are resizing brushes which are part of a curve because their faces will line up after the drag.
  • +
  • The vertices of the dragged faces are snapped to the grid planes, i.e., whenever at least one vertex component (X,Y, or Z) is a multiple of the current grid size, the face is snapped to that vertex. This makes it easy to align a face to other adjacent faces.
  • +
+

Both snap modes are used simultaneously. There may be situations when you have to move the camera closer to a face in order to have sufficient precision when dragging the face.

+

Moving Faces Instead of Extruding

+

The brush extrude tool offers a quick way to move an individual face of a brush in 2D views. Hold in addition to when starting to drag a face in a 2D view to enable this mode. You will notice that a face is highlighted as usual, but when you start dragging the mouse, the face will just be moved in the direction you are dragging. The move is not restricted by the face normal, and other faces will be affected as well.

+
+ Moving faces +
+

The distance is snapped to the current grid size. Moving multiple faces is possible if the faces lie on the same plane. The UV Lock setting controls whether alignment lock is used when dragging faces using this mode.

+

Clipping

+

Clipping is the most basic operation for Quake maps due to how brushes are constructed from planes. In essence, all that clipping does is adding a new plane to a brush and, depending on the brush’s shape, removing other planes from it if they become superfluous. In TrenchBroom, clipping is done using the clip tool, which you can activate by choosing . The clip tool lets you define a clip plane in various ways, and the lets you apply that plane to the selected brushes.

+

There are three different outcomes of applying a clip plane: Drop all parts of the selected brushes that are in front of the (oriented) clip plane, drop all parts of the selected brushes that are behind the clip plane, or slice the selected brushes into two pieces each. The following image illustrates these three modes:

+
+ The three clip modes +
+

In all three images, there is a clip plane defined by two points. This clip plane slices the single brush in the image into two parts whereby the left part is below the plane and the right part is above it. In the first image, the clip mode is set to retain the part of the brush that is below the clip plane and to discard the part that is above the clip plane. The resulting brush will be shaped like the red part of the brush in the image. In the second image, the clip mode is set to retain both parts of the brush, and the result of this clipping operation will be two brushes. In the third image, the clip mode is set to retain the part of the brush that is above the clip plane and to discard the other part. This is the opposite of the first case. In the clip tool, you can cycle through these three modes by hitting . There are two ways of defining a clip plane: The more common way is to place at least two and and most three points (in this context, these points are called clip points) in either the 3D or a 2D viewport. The other way is to define the clip plane by using an existing brush face.

+

Clip Points

+

To place clip points, you simply left click into a viewport when the clip tool is active. Alternatively, you can add two clip points at once by dragging with the left mouse. In that case, the first clip point is placed at the start point of the drag, and the second clip point is placed at the end point of the drag. In the 3D viewport, you can only place clip points on already existing brushes, whereas in the 2D viewports, you can place them anywhere. Clip points are snapped to the grid, however, in the 3D viewport, there is a caveat which we will explain below. When the clip tool is active, it gives you some feedback in the form of an orange sphere that appears close to your mouse pointer. This sphere indicates where a clip point would be placed after being snapped to the grid. This feedback sphere is only shown if a clip point can actually be placed at or close to the point under the mouse.

+

Once two clip points have been placed, TrenchBroom will attempt to guess a clip plane even though it is underspecified: You cannot define a plane with only two points. If you are happy with the clip plane that TrenchBroom has determined, then you can apply the clipping operation by hitting . Otherwise, you can place the third point to fully define the clip plane, or you can change the clip points you have already placed. To change a clip point, you can just left click and drag it with the mouse. To remove the most recently place clip point, you can choose .

+

Clip Point Snapping

+

In the 3D viewport, clip points can only be placed on the faces of already existing brushes. Such a clip point is snapped to the grid that has been projected onto the brush face on which you placed that point. So it appears to be snapped to the projected grid, but it is also kept glued onto the brush face. If the point were snapped in all dimensions, then it would either sink into or move away from the brush face it was placed on. TrenchBroom avoids this by glueing clip points to the brush faces on which they were placed by the user. This means that if you attempt to move an already placed clip point around using the 3D viewport, that point will be moved to the closest snapped point on the brush face under the mouse.

+

In the 2D viewport, clip points are just snapped to the visible grid, so they are not restricted to being glued to brush faces. You can place clip points in any viewport you wish, and you can move clip points that have been placed in one viewport using any other viewport, but the grid snapping will be that of the viewport that you are using to move the clip point. That means if you use a 2D viewport to move a clip point that was placed in the 3D viewport, then that point can be dragged off of the brush face on which it was placed and into the void. Conversely, if you use the 3D viewport to move a clip point that was placed in a 2D viewport, that clip point will snap onto the brush face under the mouse, or it will not move at all if there is no brush face under the mouse.

+

Matching Clip Plane

+

Matching a clip plane The clip plane can also be defined by matching it to an existing brush face. To match a clip plane to an existing brush face, you have to double click that face in the 3D viewport. As a result, the brush face gets an orange outline, and a clip plane is defined to match the face’s plane exactly. This can be quite useful when shaping geometry to other geometry. Note that the plane points of the clip plane are the plane points of the brush face to which the clip plane was matched, so there should be no trouble with microleaks when using this particular function.

+

Vertex Editing

+

TrenchBroom includes three separate tools to edit a brush’s vertices: the vertex tool for editing individual vertices, the edge tool for editing individual edges, and the face tool for editing individual faces. The vertex tool is the most powerful of the three because in addition to moving vertices around, you can also add and remove vertices from the brush(es). Conversely, the edge and face tools only allow you to move faces around.

+

Vertex Tool

+

Using the vertex tool, you can move individual vertices around in 3D space. Additionally, you can add vertices to a brush, and you can remove vertices from a brush. To activate the vertex tool, choose Choose . When the vertex tool is active, yellow handles appear at the vertices of the selected brushes to allow manipulation.

+
+ Vertex Handles +
+

Moving the mouse pointer over a vertex handle highlights that handle with a red circular outline, and the position of that handle is displayed above it.

+

Selecting vertex handles is treated in the same way as selecting objects. Click on a handle to select it. Multiple handles can be selected by holding . The vertex tool also allows you to select multiple handles using a selection lasso. Left drag with the mouse button to create a rectangular selection lasso. Release the left mouse button, and all handles inside the lasso are selected. If the lasso rectangle contains a vertex handle that’s already selected, then it will be deselected. To ensure that all vertex handles inside the lasso are selected regardless of their previous selection state, hold .

+

When you have selected some vertex handles, you can move them around by dragging them with the left mouse button. Moving vertex handles (and their corresponding vertices) works in a similar fashion to moving objects, so in the 3D viewport, you can move them on the XY plane, or you can hold to move them vertically. In a 2D viewport, you can move the vertex handles on the view plane of that viewport. If you begin your drag on an unselected vertex handle, that vertex handle is automatically selected, so if you just want to move a single vertex around, you do not need to select it first. Once you press the left mouse button on a vertex handle to begin a drag, yellow guide lines show up that help you to position the vertex in relation to other objects. When moving vertex handles around, the move distances are snapped to the current grid size component wise, just like when you move objects. If you prefer to have the absolute vertex positions snapped to the grid, you can toggle between relative and absolute snapping using during the drag.

+

Chopping faces TrenchBroom ensures that you do not create invalid brushes with the vertex tool. For example, it is impossible to make a brush concave by pushing a vertex into the brush. To achieve this, TrenchBroom will chop up the faces incident to that vertex into triangles depending on the direction in which that vertex is moved. In the animation on the left, you can see that the top face of the cube has one triangle chopped off in the first move where the vertex is moved downward, while in the second move, the front face is chopped into a triangle fan when the vertex is moved outward. Sometimes, TrenchBroom will even delete a vertex if a move would push it inside the brush, which would make it concave. In such a case, the vertex move is concluded.

+

The vertex tool also allows you to fuse adjacent vertices. If a vertex ends up on an adjacent vertex during a vertex move, the two vertices will be fused. This does not conclude the move however, you can keep moving the fused vertex, and it remains selected. Note that fusing is not allowed when you are moving edges or faces, even though fusing does happen when you move multiple vertices at once.

+

If you wish to snap a vertex onto another vertex quickly without performing a drag, you can just click on the target vertex while holding .

+


+

Splitting Besides moving, fusing and deleting vertices, you can also add new vertices to a brush with the vertex tool. Hold and move your mouse over the position on the grid where you wish to add a vertex. Notice that a new vertex handle is shown when your mouse pointer is close to that point. Click and drag the handle to add a new vertex.

+

Additionally, you can delete the selected vertices, edges, and faces from brushes by choosing . Note that this will only succeed if none of the currently selected brushes becomes invalid by the deletions, that is, you can only delete vertices, edges, or faces if all of the selected brushes remain three-dimensional after the deletions. If that is not the case, TrenchBroom will refuse the entire operation.

+


+

Vertex clumping Vertex editing is not limited to working with single brushes. Selecting more than one brush and activating the vertex tool will cause vertex handles to appear for all brushes in the selection. This is more useful when working on organic brushwork such as terrain. You can build a large group of brushes and modify them all at once without having to change the selection. TrenchBroom will recognize when vertices of multiple brushes share the same position. In this case, when trying to move a vertex, TrenchBroom will move all those vertices together, making editing terrain much quicker and easier. In the following animation, the vertices under the cursor were moved with a single drag operation because they share the same position.

+


+

The vertex tool also provides some keyboard shortcuts to move vertices. These are listed in the following table.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectionShortcut (2D)Shortcut (3D)
Left
Right
Up
Down
Forward
Backward
+

This concludes the functionality of the vertex tool. While it is very powerful, it should also be used with care, as vertex editing can sometimes create invalid brushes and microleaks in the map. To help you avoid such problems, the following section contains a few best practices you should keep in mind when you use the vertex tool.

+

Edge Tool

+

Using the edge tool, you can move individual edge around in 3D space. To activate the edge tool, choose Choose . When the edge tool is active, the edges of the selected brushes are rendered yellow to indicate that they allow manipulation. Furthermore, a handle appears at the center of each edge.

+
+ Edge Handles +
+

Moving the mouse pointer over an edge handle highlights that handle in red. Selecting edge handles works in the same way as selecting vertex handles. Click on a handle to select it. Multiple handles can be selected by holding . Selected handles are rendered in red. The edge tool also allows you to select multiple handles using a selection lasso. Left drag with the mouse button to create a rectangular selection lasso. Release the left mouse button, and all handles contained in the lasso are selected. If the lasso rectangle contains an edge handle that’s already selected, then it will be deselected. To ensure that all edge handles contained in the lasso are selected regardless of their previous selection state, hold .

+

When you have selected some edge handles, you can move them around by dragging them with the left mouse button. Moving edge handles (and their corresponding edges) works in same way as moving vertices, with the exception that the tool only supports relative snapping of the move distances. Like the vertex tool, the edge tool will detect if two or more brushes share an edge and move the edges of all selected brushes if a shared edge is moved.

+

Finally, the edge tool also supports the same keyboard commands as the vertex tool.

+

Face Tool

+

Using the face tool, you can move individual face around in 3D space. To activate the face tool, choose Choose . When the face tool is active, the faces of the selected brushes are rendered yellow to indicate that they allow manipulation. Additionally, the tool shows point handles at the centers of the faces; these handles allow selection and manipulation of the faces. Note that the handles allow you to select and manipulate faces which face away from the camera, too.

+
+ Face Handles +
+

Moving the mouse pointer over an face handle highlights that handle with a red outline. Additionally, the face edges are rendered thicker. Selecting face handles works in the same way as selecting vertex handles. Click on a handle to select it. Multiple handles can be selected by holding . Selected handles are rendered in red. The face tool also allows you to select multiple faces using a selection lasso. Left drag with the mouse button to create a rectangular selection lasso. Release the left mouse button, and all face handles contained in the lasso are selected. If the lasso rectangle contains a face handle that’s already selected, then it will be deselected. To ensure that all face handles contained in the lasso are selected regardless of their previous selection state, hold .

+

When you have selected some face handles, you can move them around by dragging them with the left mouse button. Moving face handles (and their corresponding faces) works in same way as moving vertices, with the exception that the tool only supports relative snapping of the move distances. Like the vertex tool, the face tool will detect if two or more brushes share an face and move the faces of all selected brushes if a shared face is moved.

+

Finally, the face tool also supports the same keyboard commands as the vertex tool.

+

Vertex Editing Best Practices

+
    +
  • Don’t use it too much on sealing brushes, better to use it on detail.
  • +
  • Don’t do too much in one go, compile and test often.
  • +
  • When doing terrain, create a quad- or trisoup and only move vertices orthogonal to the grid’s plane (along the plane’s normal). Don’t move vertices sideways.
  • +
  • Be careful with detail brushes, they might open vis portals.
  • +
  • Detail might also result in PVS leaves too much information, better to turn some detail into actual brushes to force vis to break a room into several PVS leaves. Or use hint brushes to force vis to add more leaves.
  • +
+

UV Lock

+

The regular Alignment Lock preference doesn’t apply to vertex editing - instead, there is a separate preference called UV Lock toggled with or the UV Lock toolbar button:

+
+ UV Lock toolbar button +
+

When this setting is enabled, TrenchBroom will attempt to keep vertex UV coordinates the same when using the vertex editing tools or face moving.

+

CSG Operations

+

CSG stands for Constructive Solid Geometry. CSG is a technique used in professional modeling tools to create complex shape by combining simple shapes using set operators such as union (sometimes called addition), subtraction, and intersection. However, CSG union and subtraction cannot be directly applied to brushes since they may create concave shapes which cannot be represented directly using brushes (remember that brushes are always convex). But some of these operators can be emulated with brushes. TrenchBroom supports the operations convex merge (in place of union), subtraction (emulated by creating new brushes to represent the resulting concave shape), and intersection (supported directly).

+

CSG Convex Merge

+

Convex merge takes a set of brushes as its input, computes the convex hull of all vertices of those brushes, and creates a new brush with the shape of the convex hull. The convex hull of a set of points is the smallest convex volume that contains all of the points. In the following animation, two brushes are being merged into one. The operation takes the vertices of both brushes and computes its convex hull. Some of the original brushes’ vertices end up as vertices of the convex hull, and some of them are discarded, such as the vertices at the bottom right corner of the top left brush in the 2D viewport. The discarded vertices are those which end up inside the convex hull.

+
+ CSG convex merge +
+

As you can see, the newly created brush covers some areas which were not covered by the original brushes. This follows the restriction that the resulting brush must be convex. Whether the resulting brush covers such previously void areas depends on how the input brushes are aligned with each other. To perform a convex merge, select the brushes to be merged and choose .

+

CSG Subtraction

+

CSG subtraction takes the selected brushes (the subtrahend) and subtracts them the rest of the selectable, visible brushes in the map (the minuend). Since the result of a CSG subtraction is potentially concave, TrenchBroom creates brushes that represent the concave shape by cutting up the minuend brushes using the faces of the subtrahend brushes.

+
+ CSG subtracting to create an arch +
+

The image above shows an example where an arch is created by subtraction. The result contains eight brushes that perfectly represent the arch. To perform a CSG subtraction, select the subtrahends (the brushes you want subtracted from the world) and choose .

+

To exclude brushes from the subtraction, you can hide them first with .

+

CSG Hollow

+

CSG hollow is a shortcut for subtracting a smaller version of a brush from itself. This can be useful to quickly block out rooms. Just select a brush and choose to hollow out the selected brush. The resulting walls will have a thickness of the current grid size.

+
+ CSG hollow +
+

In this example, a cube is hollowed out, leaving six brushes which form the walls, floor, and ceiling of the resulting room. Note that the wall thickness is determined by the grid size.

+

CSG Intersection

+

CSG intersection takes a set of brushes and computes their intersection, that is, it computes the largest brush that is contained in each of the input brushes. Another way to think of this is that intersection takes that part of the input brushes where they all overlap, and creates a new brush that represents that part. If there is no such part, then the input brushes are disjoint, and their intersection is empty. The input brushes are then removed from the map.

+
+ CSG intersection of two cuboids +
+

You can perform a CSG intersection by selecting the brushes you wish to intersect, and then choosing .

+

Materials and CSG Operations

+

In each of the CSG operations, new brushes are created, and TrenchBroom has to assign materials to their faces. To determine which material to assign to a new brush face, TrenchBroom will attempt to find a face in the input brushes that has the same plane as the newly created face. If such a face was found, TrenchBroom assigns the material and attributes of that brush face to the newly created brush face. Otherwise, it will assign the current material.

+
+ CSG material handling +
+

In the example above, a brush is subtracted from another brush to form an archway. The subtrahend has a blue brick material and the minuend has a dark metal material. After the subtraction, those faces of the result that line up with the faces of the subtrahend have also been assigned the blue brick material, while those faces that line up with the faces of the minuend brush have been assigned the dark metal material. Some of the faces of the result brushes are invisible because they are shared by other brushes - these faces have been assigned the current material because no face of the subtrahend or the minuend lines up with them.

+

Special Brush and Face Types

+

Most Quake based games have certain special types of brushes and faces. An example for a special brush type is a trigger brush that activates some game logic. A special face type may be a face with a special clip material that is invisible, but blocks the player from passing it. In Quake 3, caulk faces are often used to tell the bsp compiler to skip certain faces because they are invisible.

+

TrenchBroom is aware of these special brush and face types as long as they are configured in the game configuration file for a game. Special brush or face types can be detected by TrenchBroom in the following ways:

+
    +
  • Brush Types +
      +
    • Entity Classname Pattern If a brush is contained in an entity whose classname matches a certain pattern, it will receive the special brush type (example: trigger brushes).
    • +
  • +
  • Face Types +
      +
    • Material Name Pattern If a brush face has a material whose name matches a certain pattern, it will receive the special face type (example: clip textures).
    • +
    • Content Flags If a brush has one of several content flags, it will receive the special face type.
    • +
    • Surface Flags If a brush has one of several surface flags, it will receive the special face type.
    • +
    • Surface Parm If a brush has a specific surface parameter, it will receive the special face type.
    • +
  • +
+

TrenchBroom allows you to filter for special brush and face types in the filtering and rendering options. Furthermore, you can assign a keyboard shortcut to set or unset a special brush type (if supported). The following special brush and face types can be set / unset in this way:

+
    +
  • Brush Types +
      +
    • Entity Classname Pattern Can be set and unset. Setting a brush type wraps the selected brushes in a newly created entity with a classname that matches the pattern. If more than one classnames in the currently loaded entity definitions matches the pattern, a dropdown menu is shown to allow you to choose one of the options. Unsetting a brush type simply moves the selected brushes into the world.
    • +
  • +
  • Face Types +
      +
    • Material Name Pattern Can be set only. Setting a face type sets a material whose name matches the pattern on the selected faces. If more than one material in the currently loaded material collections matches the pattern, a dropdown menu is shown to allow you to choose one of the options.
    • +
    • Content Flags Can be set and unset. Setting a face type sets one of the configured content flags on the selected faces. If more than one content flag was configured, a dropdown menu is shown to allow you to choose one of the options. Unsetting clears all of the configured content flags.
    • +
    • Surface Flags Can be set and unset. Setting a face type sets one of the configured surface flags on the selected faces. If more than one surface flag was configured, a dropdown menu is shown to allow you to choose one of the options. Unsetting clears all of the configured surface flags.
    • +
    • Surface Parm Can neither be set nor unset.
    • +
  • +
+

Finally, every special brush or face type that supports unsetting can be cleared using the Make Structural command .

+

Working with Materials

+

There are two aspects to working with materials in a level editor. Material management and material application. This section deals with the latter, so you will learn different ways to apply material to brush faces and to manipulate their alignment to the faces. But before we dive into that, we have to cover three general topics: First, we present the material browser, then we explain how TrenchBroom assigns material to newly created brush faces, and finally we discuss different material projection modes in TrenchBroom.

+

The Material Browser

+

The material browser The material browser is part of the face inspector and is used for two purposes: Changing the material for the currently selected faces and selecting the current material. In the material browser, materials are displayed with a maximum width of 64 pixels - wider materials are proportionally scaled down. The name of every material is displayed below the image. materials that are currently in use have a yellow border, while the current material has a red border. If you hover over a material image with the mouse, you will see a tooltip with the name and the dimensions of the corresponding texture.

+

Below the material browser, there are the same controls as in the entity browser: A dropdown for changing the sort order (name or usage count), a button to group by material collection, a button to filter by usage, and a text field to filter by name. Multiple words (space delimited) can be used to show only materials that contain all of the words. If the size of the images is too small or too large on your monitor, you can change it in the preferences.

+

To select all faces having a certain material, right click that material in the material browser and click “Select Faces” from the popup menu.

+

Filtering Material Collections

+

Filtering material collections To filter out material collections, click on the “Settings” button in the material browser’s title bar. This reveals a UI to enable or disable individual material collections. Select one or more material collections from the “Available” section and click on the “+” icon to enable them. To disable material collections, select them in the “Enabled” section and click on the “-” icon. Click on the circular arrow icon to reload all material collections.

+

Click on the “Browser” button in the material browser’s title bar to return to the material browser.

+

Material Projection Modes

+

In the original Quake engine, materials are projected onto brush faces along the axes of the coordinate system. In practice, the engine (the compiler, to be precise), uses the normal of a brush face to determine the projection axis - the chose axis is the one that has the smallest angle with the face’s normal. Then, the material is projected onto the brush face along that axis. This leads to some distortion (shearing) that is particularly apparent for slanted brush faces where the face’s normal is linearly dependent on all three coordinate system axes. However, this type of projection, which we call paraxial projection in TrenchBroom, also has an advantage: If the face’s normal is linearly dependent on only two or less coordinate system axes (that is, it lies in the plane defined by two of the axes, e.g., the XY plane), then the paraxial projection ensures that the material still fits the brush faces without having to change the scaling factors.

+

The main disadvantage of paraxial projection is that it is impossible to do perfect alignment locking. Alignment locking means that the material remains perfectly in place on the brush faces during all transformations of the face. For example, if the brush moves by 16 units along the X axis, then the materials on all faces of the brush do not move relatively to the brush. With paraxial projection, materials may become distorted due to the face normals changing by the transformation, but it is impossible to compensate for that shearing.

+

This is (probably) one of the reasons why the Valve 220 map format was introduced for Half Life. This map format extends the brush faces with additional information about the UV axes for each brush faces. In principle, this makes it possible to have arbitrary linear transformations for the UV coordinates due to their projection, but in practice, most editors keep the UV axes perpendicular to the face normals. In that case, the material is projected onto the face along the normal of the face (and not a coordinate system axis). In TrenchBroom, this mode of projection is called parallel projection, and it is only available in maps that have the Valve 220 map format.

+

How TrenchBroom Assigns Materials to New Brushes

+

In TrenchBroom, there is the notion of a current material, which we have already mentioned previous sections. Initially, the current material is unset, and it is changed by two actions: selecting a brush face and selecting the current material by clicking on a material in the material browser. When TrenchBroom creates a new brush or a new brush face, it may consult the current material to determine which material to apply to the newly created brush faces. This is not always the case: Sometimes, TrenchBroom can determine materials for newly created brush faces from the context of the operations. We have discussed this earlier for CSG operations. In other cases, such as when you create a new brush with the mouse, TrenchBroom will always apply the current material.

+

Assigning Materials Manually

+

To change the material of the currently selected faces, left click on a material in the material browser. This also works if you have selected brushes (and nothing else) - in this case, the new material is applied to all faces of the currently selected brushes.

+

You can also transfer material and attributes from one face to another. “Attributes” in this context refers to almost any characteristic — such as offset, scale, or surface flags — that you can modify through the face attribute editor. The sole exception to this is content flags; the content flags on the target face(s) will always be preserved unchanged.

+

To do this transfer, start by selecting the source face with + left click. Then, hold one of the following modifier combinations depending on what you want to transfer:

+ + + + + + + + + + + + + + + + + + + + + +
Modifier KeysMeaning
Transfer material and attributes from selected face (by projecting it on to the target faces)
Transfer material and attributes from selected face (by rotating it on to the target faces, available on Valve format maps only)
Transfer material only (attributes of the target are preserved)
+

and perform one of the following actions, depending on which faces you want to transfer to:

+ + + + + + + + + + + + + + + + + + + + + +
ActionsFaces to transfer to
Left mouse clickclicked face
Left mouse dragall faces dragged over (each subsequent face dragged over will transfer from the last)
Left mouse double clickall faces of target brush
+

To clarify, using the modifier copies the source face’s UV axes to the target face without altering it. Sometimes this is desirable, but it can lead to the target face having a stretched material if the face normals are very different. The combination avoids this by rotating the source face’s UV axes onto the target face, but it’s only available on Valve format maps.

+

Finally, you can use copy and paste to copy the material and attributes of a selected face onto other faces:

+
    +
  1. Select the face that you wish to copy from and choose
  2. +
  3. Select the faces that you wish to copy to, and choose
  4. +
+

Replacing Materials

+

If you want to replace a particular material with another one, you can choose . This opens a window where you can select the material to be replaced and the replacement material using two material browser. This window is depicted in the following screenshot.

+
+ Material Replace Window (Mac OS X) +
+

Select the material you wish to replace in the left material browser. This browser by default only shows you the materials which are currently in use in the map. In the screenshot, the material “b_pv_v1a1” has been selected for replacement and therefore has a red border. Then select the replacement material in the right material browser (“b_sr_20c” in the screenshot). Finally, hit the “Replace” button. The replacement is applied to all brush faces in the map if nothing is currently selected. Otherwise, it is applied to the selected brush faces only. If the replacement succeeded, the faces which have been replaced are subsequently selected. Otherwise, the selection remains unchanged.

+

Setting Face Attributes

+

Face attributes control how materials are mapped onto brush faces. At the very least, every face has the attributes offset, scale, and angle. The offset allows you to shift a material on a face, the scale factors stretch the material, and by changing the angle you can rotate the material. Additionally, some engines have further attributes. Quake 2 adds surface flags and a surface value, and additional content flags. All of these values can be changed in different ways: There is a face attribute editor that allows you to enter the values directly, you can use keyboard shortcuts in the 3D viewport, or you can use the UV editor.

+

The Face Attribute Editor

+

The face attribute editor is located in the face inspector, right between the UV editor and the material browser. It contains several controls to edit the face attributes of one or several selected brush faces.

+
+ Face Attribute Editor (Mac OS X) +
+

Two types of controls are visible in the screenshot above. Numerical input controls consist of a text field and small buttons to increase or decrease the value in the field. The text field will show the value of the respective face attribute, such as “1” for the X Scale in the screenshot. If more than one brush face is selected, the text field will also show the value if all faces have the same value for the respective attribute, or it will show the placeholder word “multi” otherwise. In the screenshot above, the X Offsets of the selected brush faces differ, hence the text field shows “multi”. All other values are identical for all selected brush faces, so all other attribute editors show concrete values instead of the placeholder. By entering a number into the text field, the attribute value of all selected brush faces can be set to that value. Consequently, if you were to enter the value “32” into the X Offset editor in our example above, all selected brush faces would have this value as their X Offset afterwards.

+

The spin button however works differently. By clicking the up- or down arrow button, you can increase or decrease the value of the respective face attribute by a certain delta value, which depends on the grid settings and the currently pressed modifier keys. The following table explains which delta value is chosen in each case.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDefault pressed pressed
OffsetGrid size2 * grid size1.0
Scale0.10.250.01
Angle15°90°
+

Note that these deltas are applied to the respective attributes of every selected brush face. So if you have selected two brush faces, one with an X Offset of 0 and one with an X Offset of 8, and your current grid size is 16, clicking on the up arrow button next to the X Offset attribute editor will change the X Offsets to 16 and 24, respectively. Only entering a value in the text field will set the two X Offsets to the same value.

+

In addition to using the buttons to change the values, you can use the scroll wheel or the arrow keys when the text field has focus. Scrolling and the arrow keys follow the same rules to determine the delta values as described in the table above.

+

For attributes that represent flag values, such as the surface and content flags for Quake 2, there is a different type of control available in the face attribute editor. This control shows a textual representation of the flag values in a text field, and you can change the flags using a dropdown window that is shown if you click on the button labeled “…” next to the text field. The dropdown window contains one checkbox for each flag, and you can check or uncheck them individually.

+

The text field for content flags will display “multi” if the currently selected faces have different sets of content flags. Note that for games that support content flags, it is almost always desirable to use identical content flags on all faces of a given brush, to avoid unexpected behavior in-game; therefore if the content flags text field shows “multi” when a single brush is selected, this can be an indicator of an error that should be corrected.

+

The surface flags text field will also display “multi” if the selected faces have different sets of surface flags, but this is not necessarily a situation that needs to be corrected. It is often valid to have different surface flags on different faces of a brush.

+

Material Alignment Keyboard Shortcuts

+

The following shortcuts work in the 3D viewport, and affect all selected brushes or brush faces:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeKeysDefault pressed pressed
OffsetGrid size2 * grid size1.0
Angle15°90°
+ + + + + + + + + + + + + + + + + + + + + + + + + +
CommandKeys
Flip Horizontally
Flip Vertically
Reset alignment
Reset alignment to world aligned
+

These are interpreted relative to the 3D camera (except “Reset”). This means that pressing will move a material roughly in that direction visually, possibly increasing or decreasing the X or Y offset depending on the camera and face orientation. The angle is treated similarly: Pressing will rotate the material counterclockwise visually, and pressing will rotate it clockwise.

+

The UV Editor

+

The UV editor is located at the top of the face inspector. Using the UV editor, you can adjust the offset, the scale and the angle of the material of the currently selected brush face. Note that the UV editor is only usable if one brush face is selected. If multiple brush faces are selected, the UV editor is empty.

+
+ UV Editor +
+

The material of the current face is shown in the background of the UV editor. The material is tiled, and the tiling edges are displayed in gray. These tiling edges are called the UV grid. The shape of the currently selected brush face is displayed in white. The yellow filled circle marks the origin of the material, and the two red lines that meet at the origin mark the origin axes of the material - these are used for scaling. The larger yellow circle is a handle used for rotating the material. The UV axes are displayed in red and green at the center of the brush face.

+

To change the offset of the material in relation to the brush face, you can just click and drag the material anywhere with the left mouse button. Note that the material will snap to the vertices of the brush face to make alignment easier.

+

You can scale the material by clicking and dragging the gray UV grid lines, which will also snap to the vertices of the brush face. Scaling is relative to the origin of the material, as marked by the yellow circle. To change the scaling origin, you can left click and drag the yellow circle, or you can left click and drag the red lines meeting at the origin. The lines allow you to set the X and Y coordinates of the origin separately. The origin snaps to the vertices of the face and to its center.

+

To rotate the material about the origin, left click and drag the large yellow circle, or hold and left click and drag anywhere in the UV editor. The angle will snap to the edges of the brush face to make it easier to adjust it to the shape of the face.

+

Shearing the material is possible if the map uses a parallel projection. Shear by holding while left clicking and dragging the gray UV grid lines.

+

At the bottom of the UV editor are the following controls:

+
+ UV Editor Toolbar +
+
    +
  • Reset alignment. All attributes are reset, and in parallel projection format maps, the material is projected from the face plane. In standard format maps, acts the same as “Reset alignment to world aligned”.
  • +
  • Reset alignment to world aligned. All attributes are reset and the material is projected from an axial plane.
  • +
  • Flip material horizontally
  • +
  • Flip material vertically
  • +
  • Rotate material 90° counterclockwise
  • +
  • Rotate material 90° clockwise
  • +
  • Grid controls for subdividing the UV grid. This can be useful to align part of a larger trim sheet to the face.
  • +
+

Entity Properties

+

An entity is, essentially, a collection of properties, and a property is a key value pair where both the key and the value is a string. Some values have a special format, such as colors, points, or angles. But in general, if you are editing an entity, you will be working with strings. In TrenchBroom, you can add, remove, and edit entity properties using the entity property editor, which is located at the top of the entity inspector.

+
+ Entity Property Editor +
+

The entity property editor is split into two separate areas. At the top, there is a tabular representation of the properties of the currently selected entities and, if applicable, the defaults for those properties which are not present in the selected entities.

+

Default Entity Properties

+

The default properties are shown in italics below the actual properties of the selected entities. To hide the default properties, you can uncheck the checkbox at the bottom of the table. Default entity properties are defined in an entity definition file such as an FGD file, and their meaning depends on the game. Some games, like Quake, have builtin default values for entity properties, and the default entity properties reflect these defaults (if set up correctly in the entity definition file).

+

Other games such as Half Life don’t provide default values for entity properties, and expect the defaults to be set explicitly for every entity. If configured in the game configuration, then TrenchBroom will automatically instantiate the default entity properties (with default values) when a new entity is created. Note that not every default property will be instantiated by TrenchBroom - only those properties which have a default value configured in the entity definition file can be instantiated by TrenchBroom.

+
+ Setting Default Entity Properties +
+

Below the entity property editor, there is a small button which pops up a menu when pressed. This menu has three entries:

+
    +
  • Set existing default properties: This resets all entity properties to their default values if they have one. No entity property is added or removed, and no entity property is changed unless it has a default value.
  • +
  • Set missing default properties: This adds all default entity properties that aren’t set. Only adds new entity properties. No entity property is removed and no existing entity property is changed.
  • +
  • Set all default properties: This is a combination of the above. Every entity property having a default value is set to its default, regardless of its current value. Missing default properties are added. No entity properties are removed, and only default entity properties are changed.
  • +
+

Editing Properties

+

To select an entity property, just click in the row that represents that property in the table. The clicked field will be highlighted, indicating that it has focus. The highlight indicates that you can change the field by entering text. In the screenshot above, the “mangle” property has been selected, and its value has focus, indicating that it is ready to be changed.

+

If you are changing a lot of properties, you may wish to navigate quickly through the table. You can use the cursor keys to move focus around in the table. Alternatively, you can hit to move field by field. If the focus is on a key of some property, hitting tab will move the cursor the value field of that property, and hitting tab again will move it to the key field of the next property, and so on until you reach the end of the table. You can also move in the opposite direction by hitting . moves vertically through the list, meaning that if focus is on a property key and you hit enter, focus will move to the key of the next property in the list. Use this navigation method to mass rename property keys, for example.

+

To change the key or the value of a property, set the focus to the appropriate field in the table. If you enter some text now, that text will replace the key of the property. An alternative way to change a field is to click on it while its property is already selected. This will show an actual text field in which you can enter the text.

+

There are several ways to add a property to an entity. First, you can click on the button with the “+” label at the bottom of the table. This will insert a new property with a default name and no value into the table. Second, you can hit to add a new property. In both cases, the new property will be selected so that you can start editing its key and value right away as described above. Finally, you can add a property by changing the value of a default property. This will promote the default property to an actual property of the entity.

+

To remove entity properties, you should click the rows in the table that represent them and hit the button labeled “-” at the bottom of the table.

+

Multiple Entity Selections

+

Multiple Entity Selections If multiple entities are selected, the table will show the union of all their properties and not just those properties which all of the selected entities have in common. Properties which are not present in all of the selected entities have their names grayed out, and properties which have different values in those entities that actually have those properties are displayed with an empty value. In the screenshot, there are three light entities selected. Consequentially, the “classname” property is present in all of them and has the same value everywhere. Likewise, the “origin” property is present in all of these entities, but it has different values in each of them, so it is shown without a value. The “light”, “wait”, “angle”, and “mangle” properties on the other hand are only present in some of the selected entities, but they do have the same values in each of the entities that have them.

+

If you change an entity property when multiple entities are selected, the change gets applied to all of the selected entities, even if that requires adding that property. So if you were to change the value of the “light” property in the example above to 200, each of the selected entities will subsequently have a “light” property with the value 200, even if only a subset of the selected entities had that property before.

+

Smart Entity Property Editors

+

TrenchBroom provides special editors for the following entity properties: spawnflags, colors, and choices. These special editors are called smart property editors and are displayed below the entity property table if you select an entity property for which such an editor exists.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
TypeEditorDescription
SpawnflagsSmart Spawnflags EditorA table of checkboxes which allow you to toggle the individual spawnflag values.
ColorSmart Spawnflags EditorA color chooser control that allows you to convert between byte and float color values, and provides a list of all colors found in the map.
ChoiceSmart Spawnflags EditorA dropdown list of values. You can also enter any text into the text box.
+

Linking Entities

+

Entities can be linked using special link properties. Each link has a source and a target entity. The target entity has a property called “targetname”, and the value of that property is some arbitrary string. The source entity has a “target” or a “killtarget” property, and the value of that property is the value of the target entity’s “targetname” property. To create an entity link, you have to manually set these properties to the proper values. Currently, the names of the link properties are hardcoded into TrenchBroom, but in the future they will be read from the FGD file if appropriate. The following section explains how entity links are visualized in the editor.

+ +

Entity Links are rendered as lines in the 3D and 2D viewports. TrenchBroom provides you with four modes for entity link visualization. You can switch between these modes in the dropdown menu that is displayed when you click on the “View” button at the right of the info bar. The following table explains the four different modes.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ModeDescription
AllAlways show all entity links.
Transitive selectedShow all entity links connected to the selected entities, and any link that is reachable from the selected entities, too.
Direct selectedShow all entity links connected to the selected entities.
NoDon’t show any entity links.
+

An entity link that is connected to a currently selected entity is rendered as a red line that connects the selected entity with the source or target of that link. Other entity links are colored green.

+
+ Entity Link Visualization +
+

In the screenshot above, the link between the two info_null entities is rendered in green because neither of the entities is selected.

+

Undo and Redo

+

Almost everything that you do in TrenchBroom can be undone by choosing . This applies to every action that somehow modifies the map file (such as moving objects), but it also applies to some actions that do not change the map file, such as selection, hiding, and locking. There is no limit to how many actions you can undo, and once an action is undone, you can redo it by choosing .

+

Undo Collation and Transactions

+

Note that TrenchBroom groups certain sequences of actions into transactions which can be undone and redone as one. For example, if you select a few objects and then hide them, the objects are automatically deselected. Both the action of deselecting the objects to be hidden and hiding them are grouped together into a transaction, so when you undo, the objects will be unhidden and reselected at the same time.

+

On top of that, TrenchBroom will merge sequences of the same action if they happen within one mouse drag or within a certain time. So if you move a brush around, all steps of the move will be merged into one action, or if you move a brush around by pressing the appropriate keyboard shortcuts within a certain time, all these actions will also be merged into one. In practice, this saves memory and it allows you to undo such sequences in one fell swoop.

+

Keeping an Overview

+

If you are working on large maps, it can become cumbersome to manage the objects in the map and to keep an overview over them. Some areas may be crowded with a lot of brushes and entities so that it becomes difficult to edit a particular object that is occluded by other things. TrenchBroom provides you with a number of tools to easily keep an overview over your map and to remove clutter in crowded areas.

+

Filtering

+

To filter out certain types of objects, you can open the view dropdown window by clicking on the “View” button at the right of the info bar above the editing area.

+
+ The info bar with view dropdown (Windows 10) +
+

In the left of the view dropdown, there is a list of checkboxes that allows you to hide all entities that share the same entity definition (i.e., the same classname). Uncheck an entity definition (or a group thereof) to hide the respective entities. For quickly hiding and showing all entities, you can click on the two buttons below the list.

+

The right half of the view dropdown has several options, partitioned into three groups.

+
    +
  • Entities - here you can configure how entities are rendered in the editor.
  • +
  • Brushes - allows you to toggle on or off certain special brush or face types. These types are game specific and are read from the game configuration file.
  • +
  • Renderer - various options on how other objects are rendered.
  • +
+

Note that it is possible to add keyboard shortcuts to toggle every option in the view dropdown in the preferences.

+

Hiding and Isolation

+

If you are working on a crowded area, it can be useful to hide certain objects, or to hide everything but the objects of interest. To hide the selected objects, choose , and to isolate the selected objects, choose . To show all hidden objects, choose . All of these actions can be undone.

+

Locking

+

Locking prevents objects from being selected or edited in anyway. Locked objects are rendered with blue edges and their faces are tinted in blue, as shown in the following screenshot.

+
+ Locked Objects +
+

Objects can be locked either if you are editing an open group or if you set a layer to locked (see below). You cannot lock objects individually.

+

Groups

+

Groups allow you to treat several objects as one and to give them a name. A group can contain the following types of objects: entities, brushes, and more groups. The fact that a group can contain groups induces a hierarchy - but in practice, you will rarely create such nested groups. In the viewports, groups have their bounding box rendered in blue, and their name is displayed above them.

+

To create a group, make sure that no tool is currently active and select some objects and choose . The editor will ask you for a name. Group names need not be unique, so you can have several groups with the same name. To select a group, you can click on any of the objects contained in it. This will not select the individual object, but the entire group, which is why you can only edit all objects within a group as one. If you want to edit individual objects in a group, you have to open the group by double clicking on it with the left mouse button. This will lock every other object in the map (locked objects are not editable and rendered in blue). Once the group is opened, you can edit the individual objects in it, or you can create new objects within the group in the usual ways. Once you are done editing the group, you can close it again by left double clicking anywhere outside of the group. Finally, you can remove a group by selecting it and choosing . Note that removing a group does not remove the objects in the group from the map, the objects are merely ungrouped.

+

To add objects to an existing group, select the objects you wish to add to the group, then right click on an object already existing to that group and select “Add Objects to GROUPNAME”, where GROUPNAME is the name of the group. Likewise, you can remove objects from a group by opening that group, selecting the objects you wish to remove from the group, and selecting “Remove Objects from GROUPNAME” from the map view context menu. The removed objects are added to the current layer. If you remove all objects from a group, the group is deleted automatically.

+

Linked Groups

+

Groups can also be linked together to allow a form of instancing. Linked groups contain the same objects, but can be transformed into different positions and shapes as a whole. Changing one of the linked groups will update all the other linked groups. Linked groups are useful to build reusable structures such as doorways that you want to keep in sync. The workflow for linked groups is always the same:

+
    +
  • Create some objects that form a reusable structure, e.g. a doorway.
  • +
  • Group the objects.
  • +
  • Select the group and create a linked duplicate via the context menu or by choosing from the menu.
  • +
  • Move the duplicate to its intended position and apply further transformations to it (e.g. rotation).
  • +
  • Create more linked duplicates by duplicating a linked group in the usual way.
  • +
  • At any time, open any of the linked groups and change its contents. These changes will then be replicated into the other linked groups.
  • +
+

You can apply various transformations to linked groups such as translation, rotation, scaling, or flipping. Groups and linked groups can be nested arbitrarily, so a linked group can contain a group, or a group can contain a linked group, and linked groups can even contain linked groups.

+

It is important not to think of linked groups as instancing. In TrenchBroom, there is no fixed “primary” version of the linked group that you create instances of. Indeed, linked groups are much simpler under the hood: When you change a linked group, that group will temporarily become the “primary” version and all of its contents are copied into all of its linked siblings, independent of whether or not the contained objects were changed. With this in mind, you may think of TrenchBroom performing a manual updating process automatically for you.

+

You can add objects to linked groups or remove objects from linked groups in the usual way, and the change is reflected in the linked groups immediately. To edit an object in a linked group, open the group as usual and perform your changes. Again, the changes are reflected in the linked groups immediately.

+

Consider the following example where you have two linked groups, each containing a brush and an entity.

+
Group A
+        - Brush A
+        - Entity A
+          - "classname" "monster_army"
+          - "angle" "90"
+          - "origin" "0 0 0"
+
+        Group B (translated by 128 0 0)
+        - Brush B
+        - Entity B
+          - "classname" "monster_army"
+          - "angle" "90"
+          - "origin" "128 0 0"
+

Group B is structurally identical to Group A, but it’s translated by 128 units on the X axis. Suppose you change Brush A by moving one of its vertices. Then all contents of Group A are copied, translated by 128 on the X axis, and added to Group B, replacing its existing content. Or let’s say you set Entity B’s spawnflags to 1, then the same process happens, but this time Group Bs content is copied, translated by -128 on the X axis, and finally Group A’s contents are replaced by the copies. The result would look as follows:

+
Group A
+        - Brush A
+        - Entity A
+          - "classname" "monster_army"
+          - "angle" "90"
+          - "origin" "0 0 0"
+          - "spawnflags" "1"
+
+        Group B (translated by 128 0 0)
+        - Brush B
+        - Entity B
+          - "classname" "monster_army"
+          - "angle" "90"
+          - "origin" "128 0 0"
+          - "spawnflags" "1"
+

There are some situations in which you might not want all of your changes to be reflected in all linked groups. For example, when building a door, you will usually hook the door brushes to a trigger brush using target and targetname properties. But of course, you want to use different names for different doors so that all doors don’t open at once when one of them opens in the game. To allow these properties to have different values in different linked groups, you can protect entity properties against changes from their counterparts in a linked group.

+

Protected Entity Properties

+

Marking an entity property as protected blocks any changes to this property from the corresponding entity in a linked group. Furthermore, any changes to a protected entity property are not reflected in the corresponding entities in linked groups. Let’s consider an example again.

+
Group A
+        - Entity A
+          - "classname" "monster_army"
+          - "angle" "90"
+          - "origin" "0 0 0"
+          - "spawnflags" "1"
+
+        Group B (translated by 128 0 0)
+        - Entity B
+          - "classname" "monster_army"
+          - "angle" "90"
+          - "origin" "128 0 0"
+          - "spawnflags" "1"
+

Let’s assume you want to change Entity B’s angle, but you don’t want this change to affect Entity A. In this case, you can set the angle property of Entity B to protected before changing its value to 180. The result will look as follows.

+
Group A
+        - Entity A
+          - "classname" "monster_army"
+          - "angle" "90"
+          - "origin" "0 0 0"
+          - "spawnflags" "1"
+
+        Group B (translated by 128 0 0)
+        - Entity B
+          - "classname" "monster_army"
+          - "angle" "180" (protected)
+          - "origin" "128 0 0"
+          - "spawnflags" "1"
+

Note that Entity A’s angle property still has a value of 90. If you now change Entity A’s angle property, this change will not be reflected in Entity B either.

+

You can use the entity property editor in the entity inspector to protect entity properties. When editing an entity inside of a linked group, a new column with checkboxes appears like in the following screenshot.

+
+ Protected Entity Properties (macOS) +
+

To set a property to protected, click on its checkbox. To remove the protection, click on the checkbox again. When you set a property to unprotected, its value will be reset to the value of the corresponding unprotected properties in the other entities. In our example from above, Setting Entity B’s angle property to unprotected will reset its value to 90, which is the value from Entity A’s unprotected angle property.

+

To set all properties of one or multiple entities to unprotected, select the entities (or their containing groups) and choose .

+

Since all changes you make to a linked group are immediately replicated into the other linked groups, newly added properties show up in the linked groups right away. If you want to add a property without replicating it, you can add it as protected by clicking on the shielded + icon in the toolbar below the entity property editor (see previous screenshot). Conversely, if you want to suppress a property in a linked group, that is, you don’t want it to be created when adding it to another linked group, you can add it as a protected property and immediately delete it again. It will still be shown in the property editor until you remove its protected checkmark, but the name will be in italics, so it will look like a default property.

+

To illustrate the value of these deleted protected properties, consider the following example.

+
Group A
+        - Entity A
+          - "classname" "monster_army"
+          - "origin" "0 0 0"
+
+        Group B (translated by 128 0 0)
+        - Entity B
+          - "classname" "monster_army"
+          - "origin" "128 0 0"
+
+        Group C (translated by 0 64 0)
+        - Entity C
+          - "classname" "monster_army"
+          - "origin" "0 64 0"
+

Suppose you want to set an angle for all of the monster_army entities except for Entity A. In this case, you would first add the angle property to Entity A as a protected property, and then delete it again from Entity A. Then you would add the angle property to Entity B and give it a value. This property would be replicated into Entity C, but not Entity A because there it is protected, even though the property isn’t even present. In the following screenshot, the angle property has been set to protected and was then subsequently deleted. If you click its checkbox to remove the protection, the property will no longer show up in the entity property editor.

+
+ Protected Deleted Entity Properties (macOS) +
+

Unlinking and Separating Linked Groups

+

To unlink a linked group, select the group and choose . This will turn the linked group into a regular group again. If you select multiple linked groups from a set of mutually linked groups, the selected groups will not be turned into regular groups, but rather they will become a separate set of linked groups. This separate set of linked groups is still mutually linked to each other, but they are no longer linked to the other, unselected members of the set.

+

Note that if you remove all members of a set of linked groups, either by separation or by deleting them, the single remaining member of the set will become a regular group.

+

Visualization

+
+ Linked Groups in 3D view (macOS) +
+

Linked groups are rendered with a different color than regular groups. If you select a linked group, the editor will render arrows emanating from the selected group and ending in the other linked groups to indicate which groups will be updated when the selected group changes. These arrows are still shown if you open a linked group.

+

Linked Groups in the Map File

+

Like regular groups, linked groups are stored in the map file using func_group entities with additional, TrenchBroom specific properties. If you edit a map file with linked groups in another editor than TrenchBroom and you change objects belonging to a linked group, then that linked group is out of sync with its linked counterparts. TrenchBroom will load such groups without issue and you can keep editing them as usual. However, if you change one of the linked groups, then this group will overwrite the contents of all other linked groups, so afterwards they will be in sync again. So if you purposefully changed one of the linked groups in an external editor, and want to replicate these changes into the linked groups, just open this specific group in the editor, make change to it, and close the group again. This will update all of the linked groups and they will be in sync again.

+

Consider the following linked groups:

+
Group A
+        - Brush A
+        - Entity A
+          - "classname" "monster_army"
+          - "origin" "0 0 0"
+
+        Group B (translated by 128 0 0)
+        - Brush B
+        - Entity B
+          - "classname" "monster_army"
+          - "origin" "128 0 0"
+

In the map file, these groups would be stored as follows. Refer to the comments for information about the TrenchBroom specific properties for linked groups.

+
// entity 0
+        {
+        "classname" "func_group"
+        "_tb_type" "_tb_group"
+        "_tb_name" "group"
+        "_tb_id" "1"
+
+        // The following property is the ID of a set of linked groups.
+        // All groups with this linked group ID will be mutually linked.
+        "_tb_linked_group_id" "{38b3b39d-a165-4999-985d-d40563ce51c1}"
+
+        // The transformation that has been applied to the group as a whole.
+        // This will get updated when you transform a group by moving, rotating or scaling it.
+        "_tb_transformation" "1 0 0 128 0 1 0 0 0 0 1 0 0 0 0 1"
+
+        // brush 0
+        {
+        // faces omitted
+        }
+        }
+        // entity 1
+        {
+        "classname" "monster_army"
+        "origin" "128 0 0"
+        "_tb_group" "1"
+        }
+        // entity 2
+        {
+        "classname" "func_group"
+        "_tb_type" "_tb_group"
+        "_tb_name" "group"
+        "_tb_id" "2"
+
+        // This group entity has the same linked group ID as the previous one,
+        // so they will be linked.
+        "_tb_linked_group_id" "{38b3b39d-a165-4999-985d-d40563ce51c1}"
+
+        "_tb_transformation" "1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1"
+        // brush 0
+        {
+        // faces omitted
+        }
+        }
+        // entity 3
+        {
+        "classname" "monster_army"
+        "origin" "0 0 0"
+        "angle" "90"
+        "_tb_group" "2"
+        "_tb_protected_properties" "angle"
+        }
+

Layers

+

Layers decompose your map into several parts. For example, you might create a layer for separate rooms or areas. Layers can contain groups, entities, or brushes, and each of these objects can belong to one layer only. Each layer has a name and can be set to hidden or locked, or omitted from exported maps. Every map contains a “Default Layer” that cannot be removed.

+
+ Layer Editor +
+

The layer editor, part of the map inspector, displays all layers in your map.

+
    +
  • Omit a layer from export by clicking the hollow circle icon (the “X” indicates the layer is omitted from export)
  • +
  • Hide or show a layer by clicking on the eye icon
  • +
  • Lock or unlock a layer by clicking on the lock icon
  • +
  • Create a new layer by clicking the plus button at the bottom of the layer list
  • +
  • Remove one or more layers by selecting them and click on the minus button
  • +
+

New objects created from scratch or pasted from the clipboard are inserted into the current layer (unless you are working in a group). Objects created from other objects (e.g. by duplicating or extrusion) are inserted into the layer of the source object.

+

The current layer is indicated in the layer list by a radio button and by having its name in bold, and you can set the current layer by double clicking on a layer in the layer list.

+

Right click on a layer in the layer editor for the layer context menu:

+
    +
  • Make active layer
  • +
  • Move selection to layer
  • +
  • Select all in layer
  • +
  • Hide layer
  • +
  • Isolate layer
  • +
  • Lock layer
  • +
  • Omit from export
  • +
  • Show all Layers
  • +
  • Hide all Layers
  • +
  • Unlock All Layers
  • +
  • Lock All Layers
  • +
  • Rename Layer
  • +
  • Remove Layer
  • +
+

The map view context menu also has some layer related shortcuts.

+

Preferences

+

The preferences dialog allows you to set the game configurations, to change the view layout and control the rendering, and to customize the mouse and the keyboard shortcuts. You can open the preferences dialog by choosing . The dialog is split into four panes, each of which we will review in the following sections. Note that on Windows and Linux, the changes are only applied if you click the “OK” or “Apply” button at the bottom of the dialog, whereas on Mac OS X, the changes are applied immediately.

+

Game Configuration

+
+ Game Configuration Dialog (Mac OS X) +
+

The game configuration preference pane is where you set up the paths to the games that TrenchBroom supports. For each game, you can set the game path by clicking on the “…” button and selecting the folder in which the game is stored on your hard drive. Alternatively, you can enter a path manually in the text box, but you have to hit to apply the change.

+

Additionally, you can configure the game engines for the selected game by clicking on the ‘Configure engines…’ button.

+

Clicking the folder icon below the game list opens the folder that contains custom game configurations in a file browser.

+
+ Game Engine Configuration Dialog (Mac OS X) +
+

In this dialog, you can add a game engine profile by clicking on the ‘+’ button below the profile list on the left, and you can delete the selected profile by clicking on the ‘-’ button. To the right of the list, you can edit the details of the selected game engine profile, specifically its name and path. Similar to the game path, if you edit the engine path manually, you have to apply the changes by pressing while in the path text box. Click here to find out how to launch game engines from within TrenchBroom.

+

For some game configurations (such as for Quake, shown above) you can also optionally enter paths for a set of compilation tools. If it’s not clear what you should be specifying a path to here, then hovering over the path entry box may give you a tooltip with additional info about that compilation tool.

+

If you do enter a path here, then the name shown to the left of the path can be used as a variable in your compilation profiles for this game. Wherever that variable occurs, the path specified here will be used. For example if your path to the qbsp tool is C:\mapping\ericw-tools-v0.18.1-win64\bin\qbsp.exe, and you set that path here… then in your compilation profiles you can enter ${qbsp} wherever you need to refer to that whole qbsp.exe path.

+

The benefits of specifying your tool paths here (if the game configuration allows) are:

+
    +
  • It will be easier to create, edit, and share your compilation profiles.
  • +
  • If your tool paths need to be changed, you only have to change them here.
  • +
+

So in the example above, if you wanted to try a later version of ericw-tools that are located in a different folder like C:\mapping\ericw-tools-v0.19-win64\bin, then you would only need to change the paths in this dialog. You wouldn’t need to edit all of your compilation profiles.

+

You can also add custom game configurations to suit a particular setup (such as an engine supporting formats that TrenchBroom supports, but does not expect with that game).

+

View Layout and Rendering

+
+ View Preferences (macOS) +
+

In this preference pane, you can choose the layout of the editing area. There are four layouts available:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
LayoutDescription
One PaneOne cycleable 3D / XY / XZ / XY viewport
Two PanesOne 3D and one cycleable XY / XZ / XY viewport
Three PanesOne 3D, one XY viewport and one cycleable XZ / YZ 2D viewport
Four PanesOne 3D, one XY viewport, one XZ viewport, and one YZ viewport
+

Cycleable 2D viewports can be cycled by pressing .

+

The remaining settings affect how the viewports are rendered.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SettingDescription
BrightnessThe brightness of the textures (affects the 3D viewport, the entity and the material browser)
GridOpacity of the grid in the 3D and 2D viewports
Coordinate System AxesShow the coordinate system axes in the 3D and 2D viewports
Filter ModeTexture filtering mode in the 3D viewport
Enable multisamplingWhether rendering is antialiased
Material Browser Icon SizeThe size of the material icons in the material browser
Renderer Font SizeText size in the map viewports (e.g. entity classnames)
+

Mouse Input

+
+ Mouse Configuration Dialog (Ubuntu Linux) +
+

The mouse input preference pane allows you to change how TrenchBroom interprets mouse movements.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
SettingDescription
Mouse LookSensitivity and axis inversion for mouse look and orbiting (right click and drag)
Mouse PanSensitivity and axis inversion for mouse panning (middle click and drag)
Mouse MoveSensitivity and settings for moving the camera with the mouse. If you use a tablet, the setting “Alt+MMB drag to move camera” might make navigation easier for you.
Move KeysKeyboard shortcuts for moving around in the map, with a separate slider to control the speed.
+

Keyboard Shortcuts

+
+ Keyboard Configuration Dialog (Ubuntu Linux) +
+

In this preference pane, you can change the keyboard shortcuts used in TrenchBroom. The table lists all available shortcuts, their context, and the description. To change a keyboard shortcut, click twice (do not double click) on the shortcut in the first column of the table and enter the new shortcut. The context determines when this shortcut is available, for example, the PgDn key triggers different actions depending on whether the rotate tool is active or not. Finally, the description column explains what a shortcut does in a particular context. Sometimes a shortcut triggers different actions depending on whether the viewport in which it was used is a 3D or a 2D viewport. For example, the PgDn key can move objects backward (away from the camera) in a 2D viewport or down along the Z axis in the 3D viewport. These different actions are listed together in the description column, but they are separated with a semicolon.

+

If you open the preference dialog when a map is currently opened, the list of shortcuts will contain additional entries depending on the loaded entity configuration file and the game configuration file. For each entity and special brush or face types, the following keyboard shortcuts are available.

+
    +
  • Entity +
      +
    • View Filter > Toggle CLASSNAME visible to toggle entities with this classname visible and invisible (more info)
    • +
    • Create CLASSNAME to create entities with this classname (more info)
    • +
  • +
  • Brush / Face Type +
      +
    • View Filter > Toggle TYPE visible to toggle brushes or faces with this type visible and invisible (more info)
    • +
    • Turn selection into TYPE to set this type to the selected brushes or faces
    • +
    • Turn selection into non-TYPE to unset this type from the selected brushes or faces
    • +
  • +
+

Note that if you assign a keyboard shortcut to different actions in the same context, the shortcut creates a conflict and you cannot exit the preference pane or close the dialog until you resolve the conflict. Conflicting shortcuts are highlighted in red.

+

Advanced Topics

+

Command Repetition

+

Editing brushwork often consists of repeating the same steps over and over. As an example, consider building a spiral stair case. You start by cutting out a brush that represents one step of the stair case. Then you duplicate that brush, move it upward and rotate it about the center axis of the stair case. And the you repeat these actions for every step of the stairset. TrenchBroom has a feature called command repetition that is designed to automate some part of this process for you.

+

Repeating commands is similar to having an automatic Macro recorder. Remember that TrenchBroom already records everything you do to provide undo and redo. In addition to undoing your actions, TrenchBroom also uses the recorded information to allow you to repeat some of your most recently performed actions. In the example of the stairwell, you would want to repeat the duplication, the translation, and the rotation actions over and over with a single key stroke. The only problem is that you need to determine which of the most recently performed actions should be repeated. This is done in two ways. First, TrenchBroom automatically forgets all repeatable actions when the selection changes. So if you select some objects and choose directly after selecting some objects, nothing will happen because all repeatable actions have been discarded. Second, you can tell TrenchBroom to discard all repeatable actions by choosing . Think of this as telling TrenchBroom to start a new macro.

+

So in the case of the spiral stairwell, you would first create the brush that represents one stair. Since you don’t want to repeat whatever actions you performed to create this brush, you’ll have tell TrenchBroom to discard all repeatable commands, either by deselecting and then reselecting the brush, or by choosing the appropriate command from the menu. After that, you duplicate the brush, move it upwards, and rotate it. Then, you can repeat these steps by choosing as often as you want.

+

In summary, you can think of command repetition as a very simple macro system that allows you to have one macro that consists only of the most recently performed actions. Even though it is quite limited, it can make your life a lot easier if you get used to it.

+

Issue Browser

+

The issue browser is located at the bottom of the window. It contains a live list of issues that TrenchBroom has detected in your map. The list is live in the sense that the editor updates it automatically whenever the map changes. Be aware that TrenchBroom cannot detect all issues that may lead to compilation errors or warnings, or strange behavior in game. But it can detect some of these issues, and keeping the map free of such issues can protect you from having to spend a lot of time fixing bugs later on when your map becomes more complex. To see which types of issues TrenchBroom can detect and fix for you, click on the “Filter” button at the top right of the issue browser. This opens a dropdown list where you can toggle which types of issues TrenchBroom should check in your map. By default, all issues are enabled.

+
+ Issue Browser with Filter Dropdown +
+

Every entry in the issue list provides you with to pieces of information: the line number, if applicable, where the problematic object is located in the current map file, and a description. If you wish to find an object that caused an issue, you can select that issue in the browser to have the object(s) selected in the editor. Next you can choose to make them visible in the 3D and 2D viewports.

+
+ Issue Browser with Context Menu +
+

In addition to making you aware of issues, TrenchBroom can also fix them for you. To fix an issue, right click it and choose the appropriate fix from the “Fix” context menu. If you wish to ignore a particular issue, you can also tell TrenchBroom to hide it by choosing “Hide” in the context menu. If you wish to see all hidden issues, you can check the respective checkbox above the issue list. To make a hidden issue visible again, first show all hidden issues, then right click the issue and choose “Show” from the context menu.

+

Compiling Maps

+

TrenchBroom supports compiling your maps from inside the editor. This means that you can create compilation profiles and configure those profiles to run external compilation tools for you. Note however that TrenchBroom does not come with prepackaged compilation tools - you’ll have to download and install those yourself. The following screenshot shows the compilation dialog that comes up when choosing .

+
+ Compilation Dialog (Windows 10) +
+

This dialog allows you to create compilation profiles, which are listed on the left of the dialog. Each compilation profile has a name, a working directory, and a list of tasks. Click the ‘+’ button below the profile list to create a new compilation profile, or click the ‘-’ button to delete the selected profile. To duplicate a profile, right click on it and select “Duplicate” from the menu. If you select a profile, you can edit its name, working directory, and tasks on the right side of the dialog.

+
+
Name
+
The name of this compilation profile. Need not be unique and can even be empty. +
+
Working directory
+
A working directory for the compilation profile. This is optional, but very useful because it can be referred to as a variable when specifying the parameters of each task (see below). Variables are allowed (see below). +
+
Tasks
+
A list of tasks which are executed sequentially when the compilation profile is run. +
+
+

The checkbox on each task lets you selectively exclude a task from running when you run the compilation profile.

+

There are three types of tasks, each with different parameters:

+
+
Export Map
+

Exports the map to a file. This file should be different from the actual file where the map is stored.

+

Layers marked “Omit From Export” will not be present in the exported map.

+ + + + + + + + + + + + + +
ParameterDescription
TargetThe path of the exported file. Variables are allowed.
+
+
Run Tool
+

Runs an external tool and captures its output. Note that for the Tool parameter’s value, you can use a compilation tool variable defined in the game configuration, as discussed below.

+ + + + + + + + + + + + + + + + + +
ParameterDescription
ToolThe absolute path to the executable of the tool that should be run. The working directory is set to the profile’s working directory if configured. Variables are allowed.
ParametersThe parameters that should be passed to the tool when it is executed. Variables are allowed.
+
+
Copy Files
+

Copies one or more files.

+ + + + + + + + + + + + + + + + + +
ParameterDescription
SourceThe file(s) to copy. To specify more than one file, you can use wildcards (*,?) in the filename. Variables are allowed.
TargetThe directory to copy the files to. The directory is recursively created if it does not exist. Existing files are overwritten without prompt. Variables are allowed.
+
+
Rename File
+

Renames or moves one file.

+ + + + + + + + + + + + + + + + + +
ParameterDescription
SourceThe file to rename or move. Wildcards are not supported. Variables are allowed.
TargetThe new path for the file. The path must end in a filename. The containing directory is recursively created if it does not exist. Existing files are overwritten without prompt. Variables are allowed.
+
+
Delete Files
+

Deletes one or more files.

+ + + + + + + + + + + + + +
ParameterDescription
TargetThe file(s) to delete. To specify more than one file, you can use wildcards (*,?) in the filename. Variables are allowed.
+
+
+

You can use expressions when specifying the working directory of a profile and also for the task parameters. The following table lists the available variables, their scopes, and their meaning. A scope of ‘Tool’ indicates that the variable is available when specifying tool parameters. A scope of ‘Workdir’ indicates that the variable is only available when specifying the working directory. Note that TrenchBroom helps you to enter variables by popping up an autocompletion list.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
VariableScopeDescription
WORK_DIR_PATHToolThe full path to the working directory.
MAP_DIR_PATHTool, WorkdirThe full path to the directory where the currently edited map is stored.
MAP_BASE_NAMETool, WorkdirThe base name (without extension) of the currently edited map.
MAP_FULL_NAMETool, WorkdirThe full name (with extension) of the currently edited map.
GAME_DIR_PATHTool, WorkdirThe full path to the current game as specified in the game preferences.
MODSTool, WorkdirAn array containing all enabled mods for the current map.
APP_DIR_PATHTool, WorkdirThe full path to the directory containing the TrenchBroom application binary.
CPU_COUNTToolThe number of CPUs in the current machine.
+

If the game configuration for the current game includes compilation tools, then the names of those tools are also available as variables in the Tool scope. The following screenshot is a section of a compilation profile showing the use of such variables.

+
+ Compilation Dialog Section, with Tool Variables (Ubuntu Linux) +
+

It is recommended to use the following general process for compiling maps and to adapt it to your specified needs:

+
    +
  1. Set the working directory to ${MAP_DIR_PATH}.
  2. +
  3. Add an Export Map task and set its target to ${WORK_DIR_PATH}/${MAP_BASE_NAME}-compile.map.
  4. +
  5. Add Run Tool tasks for the compilation tools that you wish to run. Use the expressions ${MAP_BASE_NAME}-compile.map and ${MAP_BASE_NAME}.bsp to specify the input and output files for the tools. Since you have set a working directory, you don’t need to specify absolute paths here.
  6. +
  7. Finally, add a Copy Files task and set its source to ${WORK_DIR_PATH}/${MAP_BASE_NAME}.bsp and its target to ${GAME_DIR_PATH}/${MODS[-1]}/maps. This copies the file to the maps directory within the last enabled mod.
  8. +
+

The last step will copy the bsp file to the appropriate directory within the game path. You can add more Copy Files tasks if the compilation produces more than just a bsp file (e.g. lightmap files). Alternatively, you can use a wildcard expression such as ${WORK_DIR_PATH}/${MAP_BASE_NAME}.* to copy related files.

+

To run a compilation profile, click the ‘Run’ button in the compilation dialog. Note that the ‘Run’ button changes into a ‘Stop’ button once the compilation profile is running. If you click on this button again, TrenchBroom will terminate the currently running tool. A running compilation will also be terminated if you close the compilation dialog or if you close the main window, but TrenchBroom will ask you before this happens. Note that the compilation tools are run in the background. You can keep working on your map if you wish.

+

If you want to test your compilation profile without actually running it, click the ‘Test’ button. A test run will only print what each task will do without actually executing it.

+

Once the compilation is done, you can launch a game engine and check out your map in the game. The following section explains how you can configure game engines and launch them from within the editor.

+

Launching Game Engines

+

Before you can launch a game engine in TrenchBroom, you have to make your engine(s) known to TrenchBroom. You can do this by bringing up the game engine profile dialog either from the launch dialog (see below) or from the game configuration.

+

There are two ways to launch a game engine from within TrenchBroom. Either click the ‘Launch’ button in the compilation dialog or choose . This brings up the launch dialog shown in the following screenshot.

+
+ Launch Dialog (Mac OS X) +
+

In this dialog, you can select the game engine of choice, edit its parameters, and launch the engine. To select an engine, click on it in the list on the right hand side of the dialog. If you wish to edit the list of engines, you can bring up the game engine profile dialog by clicking on the ‘Configure engines…’ button. You can then edit its parameters in the text box at the bottom of the left hand side of the dialog. Note that you can use the following variables in this text box:

+ + + + + + + + + + + + + + + + + + + + + +
VariableDescription
MAP_BASE_NAMEThe base name (without extension) of the currently edited map.
GAME_DIR_PATHThe full path to the current game as specified in the game preferences.
MODSAn array containing all enabled mods for the current map.
+

The MODS variable is useful to pass a parameter to the engine to choose a mod. Usually, this will be the last mod in the mods for the current map. Since the MODS variable is an array that contains all mods for the map, its individual entries are accessed using the subscript operator (see below). To access the last entry in the array, you can use the expression $MODS[-1].

+

Note that the parameters are stored with the game engine profile.

+

Expression Language

+

TrenchBroom contains a simple expression language that can be used to easily embed variables and more complex expressions into strings. Currently, the language is mainly used in the Compilation dialog and the Launch Engine dialog. In the following, we will introduce the syntax and the semantics of the expression language.

+

Evaluation

+

Every expression can be evaluated to a value. For example, the string "This is a string." is a valid expression that will be evaluated to a value of type String containing the string This is a string.. The expression language defines the following types.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDescription
BooleanA value of this type can either be true or false.
StringA string of characters.
NumberA floating point number.
ArrayAn array is a list of values.
MapA map is a list of key-value pairs. Synonyms: dictionary, table.
RangeThe range type is only used internally.
NullThe type of null values.
UndefinedThe type of undefined values.
+

Type Conversion

+

The following matrix describes the possible type conversions between these types. The first column contains the source type, while the following columns describe how a type conversion takes place, or if the result is an error. Note that the columns for types Range, Null, and Undefined are omitted because not type can be converted to these types (except for the trivial conversions). Converting a value of a some type X to the same type is called trivial.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BooleanStringNumberArrayMap
Booleantrivial"true" or "false"1.0 or 0.0errorerror
Stringfalse if value is "false" or "", true otherwisetrivial0.0 if blank, number representation if possible, error otherwiseerrorerror
Numberfalse if value is 0.0, true otherwisestring representation, e.g. “1.0”trivialerrorerror
Arrayerrorerrorerrortrivialerror
Maperrorerrorerrorerrortrivial
Rangeerrorerrorerrorerrorerror
Nullfalse"" (empty string)0.0empty arrayempty map
Undefinederrorerrorerrorerrorerror
+

A string value can be converted to a number value if and only if the string is a number literal (see below). Conversely, any number can always be converted to a string value, and the number is formatted as follows. If the number is integer, then only the decimal part and no fractional part will be added to the string. If the number is not integer, the fractional part will be formatted with a precision of 17 places.

+

Expressions and Terms

+

Every expression is made of one single term. A term is something that can be evaluated, such as an addition (7.0 + 3.0) or a variable (which is then evaluated to its value).

+
Expression     = GroupedTerm | Term
+        GroupedTerm    = "(" Term ")"
+        Term           = SimpleTerm | Switch | CompoundTerm
+
+        SimpleTerm     = Name | Literal | Subscript | UnaryTerm | GroupedTerm
+        CompoundTerm   = AlgebraicTerm | LogicalTerm | ComparisonTerm | Case
+
+        UnaryTerm      = Plus | Minus | LogicalNegation | BinaryNegation
+        AlgebraicTerm  = Addition | Subtraction | Multiplication | Division | Modulus
+        LogicalTerm    = LogicalAnd | LogicalOr
+        BinaryTerm     = BinaryAnd | BinaryXor | BinaryOr | BinaryLeftShift | BinaryRightShift
+        ComparisonTerm = Less | LessOrEqual | Equal | Inequal | GreaterOrEqual | Greater
+

Names and Literals

+

A name is a string that begins with an alphabetic character or an underscore, possibly followed by more alphanumeric characters and underscores.

+
Name = ( "_" | Alpha ) { "_" | Alpha | Numeric }
+

MODS, _var1, _123 are all valid names while 1_MODS, $MODS, _$MODS are not. When an expression is evaluated, all variable names are simply replaced by the values of the variables they reference. If a value is not of type String, it will be converted to that type. If the value is not convertible to type String, then an error will be thrown.

+

A literal is either a string, a number, a boolean, an array, or a map literal.

+
Literal = String | Number | Boolean | Array | Map
+
+        Boolean = "true" | "false"
+        String  = """ { Char } """ | "'" { Char } "'"
+        Number  = Numeric { Numeric } [ "." Numeric { Numeric } ]
+

Note that strings can either be enclosed by double or single quotes, but you cannot mix these two styles. If you enclose a string by double quotes, you need to escape all literal double quotes within the string with backslashes like so: “this is a \”fox\"", but this is not necessary when using single quotes to enclose that string: ‘this is a “fox”’ is also a valid string literal.

+

Further note that number literals need not contain a fractional part and can be written like integers, i.e. 1 instead of 1.0.

+

Array literals can be specified by giving a comma-separated list of expressions or ranges enclosed in brackets.

+
Array      = "[" [ ExpOrRange { "," ExpOrRange } ] "]"
+        ExpOrRange = Expression | Range
+        Range      = Expression ".." Expression
+

An array literal is a possibly empty comma-separated list of expressions or ranges. A range is a special type that represents a range of integer values. Ranges are specified by two expressions separated by two dots. A range denotes a list of number values, so both expressions must evaluate to a value that is convertible to type Number. The first expression denotes the starting value of the range, and the second expression denotes the ending value of the range, both of which are inclusive. The range 1.0..3.0 therefore denotes the list 1.0, 2.0, 3.0. Note that the starting value may also be greater than the ending value, e.g. 3.0..1.0, which denotes the same list as 1.0..3.0, but in the opposite order.

+

The following table gives some examples of valid array literal expressions.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExpressionValue
[]An empty array.
[1,2,3]An array containing the values 1.0, 2.0, and 3.0.
[1..3]An array containing the values 1.0, 2.0, and 3.0.
[1,2,4..6]An array containing the values 1.0, 2.0, 4.0, 5.0, and 6.0.
[1+1,3.0]An array containing the values 2.0 and 3.0.
[-5,-1]An array containing the values -5.0, -4.0, …, -1.0.
+

A map is a comma-separated list of of key-value pairs, enclosed in braces. Note that keys are strings or names. To use certain special characters or whitespace in the key, it must be given as a string. The value is separated from the key by a colon character.

+
Map          = "{" [ KeyValuePair { "," KeyValuePair } ] "}"
+        KeyValuePair = StringOrName ":" Expression
+        StringOrName = String | Name
+

An example of a valid map expression looks as follows:

+
{
+          "some key":  "a string",
+          other_key:   1+2,
+          another_key: [1..3]
+        }
+

This expression evaluates to a map containing the value "a string" under the key some key, the value 3.0 under the key other_key, and an array containing the values 1.0, 2.0, and 3.0 under the key another_key.

+

Subscript

+

Certain values such as strings, arrays, or maps can be subscripted to access some of their elements.

+
Subscript     = SimpleTerm "[" ExpOrAnyRange { "," ExpOrAnyRange } "]"
+        ExpOrAnyRange = ExpOrRange | AutoRange
+        AutoRange     = ".." Expression | Expression ".."
+

A subscript expression comprises of two parts: The expression that is being indexed and the indexing expression. The former can be any expression that evaluates to a value of type String, Array or Map, while the latter is a list of expressions or ranges. Depending of the type of the expression being subscripted, only certain values are allows as indices. The following sections explain which types of indexing values are permissible for the three subscriptable types.

+

Subscripting Strings

+

The following table explains the permissible indexing types and their effects.

+ + + + + + + + + + + + + + + + + +
IndexEffect
NumberReturns a string containing the character at the specified index or the empty string if the index is out of bounds. Negative indices are allowed.
ArrayReturns a string containing the characters at the specified indices. Assumes that all elements of the array are convertible to Number. Indices that are out of bounds are ignored, but negative indices are allowed.
+

If an index value is of type Number, it is rounded towards the closest integer towards 0, that is, the value 1.7 is rounded down to 1, while the value -2.3 is rounded up to -2. String subscripts are very powerful because they allow multiple subscript index values and even negative indices. Here are some examples for using string subscripts.

+
"This is a test."[0]  // "T"
+        "This is a test."[1]  // "h"
+

Multiple indices, or array indices, can be used to extract substrings. Range expressions are a shorter way of extracting substrings.

+
"This is a test."[0, 1, 2, 3] // "This"
+        "This is a test."[0..3]       // "This"
+        "This is a test."[5..6]       // "is"
+

You can even use multiple range expressions in a subscript, and you can combine range expressions and single indices, too.

+
"This is a test."[0..3, 5..6]    // "Thisis"
+        "This is a test."[0..3, 5..6, 8] // "Thisisa"
+

Negative indices can be used to extract a string suffix. Note that the index value -1 accesses the last character of the array, the value -2 accesses the last but one character, and so on. Assuming that the string that is being subscripted has a length of 7, then the value -7 accesses the string’s first character.

+
"This is a test."[-1]     // "."
+        "This is a test."[-5..-2] // "test"
+

You can even reverse strings using subscripts and ranges.

+
"This is a test."[14..0] // .tset a si sihT
+

Auto ranges are special constructs that are only permissible in subscript expressions. An auto range is a range where the start or end is unspecified. The unspecified side of an auto range is automatically replaced by the length of the string minus one.

+
"This is a test."[..0] // .tset a si sihT
+        "This is a test."[5..] // "is a test."
+

Subscripting Arrays

+

The following table explains the permissible indexing types and their effects.

+ + + + + + + + + + + + + + + + + +
IndexEffect
NumberReturns the value at the specified index. An error is thrown if an the index is out of bounds. Negative indices are allowed. The same rounding rules as for string subscripts are applied.
ArrayReturns an array containing the values at the specified indices. Assumes that all elements of the indexing array are convertible to Number. If the indexing array contains an index that is out of bounds, an error is thrown. Negative indices are allowed.
+

Just like string subscripts, array subscripts are very powerful because they allow multiple subscript index values and even negative indices. For the following examples, assume that the variable arr is the following array:

+
[ 7, 8, 9, "test", [ 10, 11, 12 ] ]
+

Simple subscripting with integer indices behaves as expected:

+
arr[0] // 7
+        arr[3] // "test"
+        arr[4] // [10, 11, 12]
+

Multiple indices, or array indices, can be used to extract sub arrays. Range expressions are a shorter way of extracting sub arrays.

+
arr[0, 1, 2, 3] // [ 7, 9, 9, "test" ]
+        arr[0..3]       // [ 7, 9, 9, "test" ]
+        arr[3..4]       // [ "test", [ 10, 11, 12 ] ]
+

You can even use multiple range expressions in a subscript, and you can combine range expressions and single indices, too.

+
arr[0..1, 3..4] // [ 7, 8, "test", [ 10, 11, 12 ] ]
+        arr[0..3, 4]    // [ 7, 8, 9, "test", [ 10, 11, 12 ] ]
+

Negative indices can be used to extract an array suffix. Note that the index value -1 accesses the last element of the array, the value -2 accesses the last but one element, and so on. Assuming that the array that is being subscripted has a length of 7, then the value -7 accesses the array’s first element.

+
arr[-2]     // "test"
+        arr[-2..-1] // [ "test", [ 10, 11, 12 ] ]
+

You can even reverse arrays using subscripts and ranges.

+
arr[4..0] // [ [ 10, 11, 12 ], "test", 9, 8, 7 ]
+

Auto ranges are special constructs that are only permissible in subscript expressions. An auto range is a range where the start or end is unspecified. The unspecified side of an auto range is automatically replaced by the length of the array minus one.

+
arr[..0] // [ [ 10, 11, 12 ], "test", 9, 8, 7 ]
+        arr[3..] // [ "test", [ 10, 11, 12 ] ]
+

Since arrays can contain other subscriptable values such as strings, arrays, and maps, you can use multiple subscript expressions to access nested elements.

+
arr[3][2..3] // "st"
+        arr[4][1]    // 11
+

Subscripting Maps

+

The following table explains the permissible indexing types and their effects.

+ + + + + + + + + + + + + + + + + +
IndexEffect
StringReturns the value under the given key or the special value undefined if the map being indexed does not contain the given key.
ArrayReturns a map containing the key-value pairs with the given keys. Assumes that all elements of the indexing array are of type String. Keys that are not contained in the map being indexed are ignored.
+

For the following example, assume that the value of variable map is the following map:

+
{
+          "some number": 1.0,
+          "some string": "test",
+          "some array" : [ 1, 2, 3, 4 ],
+          "some map"   : { "key1": 5, "key2": "asdf" }
+        }
+

We begin with simple indexing using strings:

+
map["some number"] // 1.0
+        map["some array"]  // [ 1, 2, 3, 4 ]
+        map["missing key"] // undefined
+

Multiple indices, or array indices, can be used to extract sub maps. Range expressions are not available for map subscripts because the generate lists of numbers and maps require the indexing values to be of type String. Indexing values that are not present in the map are ignored.

+
map["some number", "some string"] // { "some number": 1.0, "some string": "test" }
+        map["some number", "missing"]     // { "some number": 1.0 }
+

Like arrays, maps can contain other subscriptable values such as strings, arrays, and maps. You can use multiple subscript expressions to access nested elements.

+
map["some array"][1]          // 2
+        map["some map"]["key2"]       // "asdf"
+        map["some map"]["key2"][1..3] // "ey2"
+

Unary Operator Terms

+

A unary operator is an operator that applies to a single operand. In TrenchBroom’s expression language, there are four unary operators: unary plus, unary minus, logical negation, and binary negation.

+
Plus            = "+" SimpleTerm
+        Minus           = "-" SimpleTerm
+        LogicalNegation = "!" SimpleTerm
+        BinaryNegation  = "~" SimpleTerm
+

The following table explains the effects of applying the unary operators to values depending on the type of the values.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operator `BooleanStringNumberArrayMapRangeNullUndefined`
Plusconvert to numbersee belowno effecterrorerrorerrorerrorerror
Minusconvert to number and negate valuesee belownegate valueerrorerrorerrorerrorerror
LogicalNegationinvert valueerrorerrorerrorerrorerrorerrorerror
BinaryNegationerrorsee belowinvert bitserrorerrorerrorerrorerror
+

Note on using applying a unary operator to a value of type String: Every operator except LogicalNegation will try to convert a value of type String to a number if possible.

+

Some examples of using unary operators follow.

+
+1.0   //  1.0
+        -1.0   // -1.0
+        -'1'   // -1.0
+        +true  //  1.0
+        -true  // -1.0
+        !true  // false
+        !false // true
+        ~1     // -2
+        ~-2    // 1
+        ~'-2'  // 1
+

Binary Operator Terms

+

A binary operator is an operator that takes two operands. Binary operators are specified in infix notation, that is, the first operator is specified first, then the operator symbol, and finally the second operator. Note that in the following EBNF notation for binary operators, the second operator is always an expression.

+

Algebraic Terms

+

Algebraic terms are terms that use the binary operators +, -, *, /, or %.

+
Addition       = SimpleTerm "+" Expression
+        Subtraction    = SimpleTerm "-" Expression
+        Multiplication = SimpleTerm "*" Expression
+        Division       = SimpleTerm "/" Expression
+        Modulus        = SimpleTerm "%" Expression
+

All of these operators can be applied to operands of type Boolean or Number. If an operand is of type Boolean, it is converted to type Number before the operation is applied.

+

If one of the operators is of type Boolean or Number and the other operand is of type String, and its value can be converted to a number, then the operand can be applied, and the operand of type String is also converted to type Number.

+
"1.23" + 1 // 2.23
+        1.23 + "1" // 2.23
+        "1" + "2"  // 12, see below
+

In addition, the + operator can be applied if both operands are of type String, if both are of type Array, or if both are of type Map.

+
"This is" + " " + "test." // "This is a test."
+        [ 1, 2, 3 ] + [ 3, 4, 5 ] // [ 1, 2, 3, 3, 4, 5 ]
+

In the previous two examples, the operands are simply concatenated. If both operands are of type Map however, the two maps are merged, that is, duplicate keys are overwritten by the values in the second operand:

+
{ 'k1': 1, 'k2': 2, 'k3': 3 } + { 'k3': 4, 'k4': 5 } // { 'k1': 1, 'k2': 2, 'k3': 4, 'k4': 5 }
+

Note that the value under key 'k3' is 4 and not 3!

+

Logical Terms

+

Logical terms can be applied to if both operands are of type Boolean. If one of the operands is not of type Boolean, an error is thrown.

+
LogicalAnd = SimpleTerm "&&" Expression
+        LogicalOr  = SimpleTerm "||" Expression
+

The following table shows the effects of applying the logical operators.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LeftRight&&||
truetruetruetrue
truefalsefalsetrue
falsetruefalsetrue
falsefalsefalsefalse
+

Binary Terms

+

Binary terms manipulate the bit representation of operands of type Number. Note that, since manipulating the bit representation of a floating point number does not make much sense, the operands are converted to an integer representation first by omitting their fractional portion. If either of the operands is not of type Number, the operand is converted to type Number according to the type conversion rules.

+
BinaryAnd        = SimpleTerm "&" SimpleTerm
+        BinaryXor        = SimpleTerm "|" SimpleTerm
+        BinaryOr         = SimpleTerm "^" SimpleTerm
+        BinaryShiftLeft  = SimpleTerm "<<" SimpleTerm
+        BinaryShiftRight = SimpleTerm ">>" SimpleTerm
+

Here are some examples of the operators in use:

+
1 & 0  // 0
+        1 | 0  // 1
+        3 & 1  // 1
+        2 | 1  // 3
+        1 ^ 1  // 0
+        1 ^ 0  // 1
+        3 ^ 1  // 2
+        1 << 1 // 2
+        2 >> 1 // 1
+

Comparison Terms

+

Comparison operators always return a boolean value depending on the result of the comparison.

+
Less           = SimpleTerm "<"  Expression
+        LessOrEqual    = SimpleTerm "<=" Expression
+        Equal          = SimpleTerm "==" Expression
+        InEqual        = SimpleTerm "!=" Expression
+        GreaterOrEqual = SimpleTerm ">=" Expression
+        Greater        = SimpleTerm ">"  Expression
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LeftRightEffect
BooleanBooleantrue is greater than false
BooleanNumberConvert right to Boolean and compare.
BooleanStringConvert right to Boolean and compare.
BooleanArrayerror
BooleanMaperror
BooleanRangeerror
BooleanNullLeft is greater than right.
BooleanUndefinedLeft is greater than right.
NumberBooleanConvert left to Boolean and compare.
NumberNumberCompare as numbers.
NumberStringConvert right to Number and compare.
NumberArrayerror
NumberMaperror
NumberRangeerror
NumberNullLeft is greater than right.
NumberUndefinedLeft is greater than right.
StringBooleanConvert left to Boolean and compare.
StringNumberConvert left to Number and compare.
StringStringCompare lexicographically (case sensitive).
StringArrayerror
StringMaperror
StringRangeerror
StringNullLeft is greater than right.
StringUndefinedLeft is greater than right.
ArrayBooleanerror
ArrayNumbererror
ArrayStringerror
ArrayArrayCompare lexicographically.
ArrayMaperror
ArrayRangeerror
ArrayNullLeft is greater than right.
ArrayUndefinedLeft is greater than right.
MapBooleanerror
MapNumbererror
MapStringerror
MapArrayerror
MapMapCompare key-value pairs lexicographically (key first, then value).
MapRangeerror
MapNullLeft is greater than right.
MapUndefinedLeft is greater than right.
RangeAny typeerror
NullNullBoth are equal.
NullUndefinedBoth are equal
NullAny typeRight is greater than left.
UndefinedNullBoth are equal.
UndefinedUndefinedBoth are equal
UndefinedAny typeRight is greater than left.
+

The following examples show the comparison operators in action with different operand types. Assume that all expressions evaluate to true unless otherwise stated in comments.

+
true > false
+        true == true
+        false == false
+
+        true == "true"
+        true == "True"
+        true == "asdf"
+        true != ""
+        true != "false"
+        true == "False"
+        true == 1
+        true == 2
+        true != 0
+
+        1 == "1"
+        1 == "1.0"
+        1 < "2"
+        1 == "asdf" // throws an error because "asdf" cannot be converted to Number
+
+        "asdf" == "asdf"
+        "asdf" < "bsdf"
+
+        null == null
+        null == undefined
+        null < -1
+        null < "asdf"
+
+        [ 1, 2, 3 ] == [ 1, 2, 3 ]
+        [ 1, 2, 3 ] <  [ 2, 2, 3 ]
+        [ 1, 2 ]    <  [ 1, 2, 3 ]
+

Case Term

+

The case operator allows for conditional evaluation of expressions. This is usually most useful in combination with the switch operator, which is explained in the next subsection.

+
 Case = SimpleTerm "->" Expression
+

In a case expression, the part before the -> operator is called the premise and the part after it is called the conclusion. The case operator is evaluated as follows:

+
    +
  • If the premise evaluates to a value r that is convertible to boolean: +
      +
    • If r converts to true: +
        +
      • The result of the case expression is the result of evaluating the conclusion.
      • +
    • +
    • Otherwise, the result of the case expression is undefined.
    • +
  • +
  • Otherwise, an error is thrown.
  • +
+

The following examples demonstrate the semantics of the case operator:

+
true   -> false  // false
+        false  -> true   // undefined
+        1      -> "test" // "test", because 1 converts to true
+        0      -> "test" // undefined, because 0 converts to false
+        "true" -> ""     // "", because "true" converts to true
+        ""     -> ""     // undefined, because "" converts to false
+

Switch Term

+

The switch operator comprises of zero or more sub expressions and its evaluation returns the result of the first expression that does not evaluate to undefined. In combination with the case operator, it implements a piecewise defined function.

+
Switch = "{{" [ Expression { "," Expression } ] "}}"
+

The following example demonstrates a very simple if / then / else use of the switch term.

+
{{
+          x == 0 -> 'x equals 0',
+          x == 1 -> 'x equals 1'
+        }}
+

This expression evaluates to the string 'x equals 0' if the value of the variable x equals 0 and it evaluates to the string 'x equals 1' if the value of the variable x equals 1. In all other cases, the switch expression evaluates to undefined.

+

But what if we wanted to have a default result for all those other cases? That’s easy with the switch expression.

+
{{
+          x == 0 -> 'x equals 0',
+          x == 1 -> 'x equals 1',
+          true   -> 'otherwise'   // the default case
+        }}
+

However, due to how the sub expressions of the switch expression are evaluated, we can abbreviate the default case:

+
{{
+          x == 0 -> 'x equals 0',
+          x == 1 -> 'x equals 1',
+                    'otherwise'   // the default case
+        }}
+

Remember that the switch expression will return the value of the first expression that does not evaluate to undefined. Since the first two sub expressions do evaluate to undefined, and the string 'otherwise' is not undefined, the switch expression will return 'otherwise' as its result.

+

Binary Operator Precedence

+

Since an expression can be another instance of a binary operator, you can simply chain binary operators and write 1 + 2 + 3. In that case, operators of the same precedence are evaluated from left to right. The following table explains the precedence of the available binary operators. In the table, higher numbers indicate higher precedence.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OperatorNamePrecedence
*Multiplication12
/Division12
%Modulus12
+Addition11
-Subtraction11
<<Bitwise shift left10
>>Bitwise shift right10
<Less9
<=Less or equal9
>Greater9
>=Greater or equal9
==Equal8
!=Inequal8
&Bitwise and7
^Bitwise xor6
|Bitwise or5
&&Logical and4
||Logical or3
..Range2
->Case1
Other operators13
+

Some examples:

+
2 * 3 + 4       // 10 because * has a higher precedence than +
+        7 < 10 && 8 < 3 // comparisons are evaluated before the logical and operator
+

If the builtin precedence does not reflect your intention, you can use parentheses to force an operator to be evaluated first.

+
2 * (3 + 4) // 14
+

Terminals

+

In EBNF, terminal rules are those which only contain terminal symbols on the right hand side. A symbol is terminal if it is enclosed in double quotes. Note that for the Char rule, we have chosen to not enumerate all actual ASCII characters and have used a placeholder string instead.

+
Alpha   = "a" | "b" | ... "z" | "A" | "B" | ... "Z"
+        Numeric = "0" | "1" | ... "9"
+        Char    = Any ASCII character
+

This concludes the manual for TrenchBroom’s expression language.

+

Solving Problems

+

This section contains some information about what you can do if you run into problems when using TrenchBroom.

+

Automatic Backups

+

TrenchBroom automatically creates backups of your work. As a prerequisite, you have to work on a saved file, that is, a file that exists somewhere on your computer. So when you create a new file, you should save it as soon as you decide that you want to keep it. At that point, TrenchBroom will create its automatic backups. These backups are stored in a folder called “autosave” within the folder where your map file is located. It will create a new backup every ten minutes after the last backup, unless the map file has not been changed since then. To prevent the autosaving from interrupting your workflow, TrenchBroom will only create an autosave you are not interacting with it, however. In total, TrenchBroom will create up to 50 backups. After that, it will delete the oldest backup when it creates a new one so that the total number of backups does not exceed 50. The backups have the same name as the map file you are editing, but with the backup number added to the name just before the extension.

+

You can use these backups to go back to previous versions of your map if problems arise. This may help you when you are fixing bugs or if your map file gets corrupted somehow.

+

Display Models for Entities

+

TrenchBroom can show models for point entities in the 3D and 2D viewports. For this to work, the display models have to be set up in the entity definition file, and the game path has to be set up correctly in the game configuration. For most of the included entity definition files, the models have already been set up for you, but if you wish to create an entity definition file for a mod that works well in TrenchBroom, you have to add these model definitions yourself. You will learn how to do this for FGD and DEF files in this section.

+

General Model Syntax

+

The syntax for adding display models is identical in all entity definition files, only the place where the model definitions have to be inserted into the entity definitions varies. We will first explain the general syntax here. Every model definition in a DEF or an FGD takes the following form:

+
model(...)
+

In ENT files, the model definitions are given as XML attribute values of the <point /> element, e.g.

+
<point model="..." />
+

Thereby, the ellipsis contains the actual information about the model to display. You can use TrenchBroom’s expression language to define the actual models. Each entity definition should contain only one model definition, and the expression in the model definition should evaluate either to a value of type string or to a value of type map. If the expression evaluates to a map, it must have the following structure:

+
{
+          "path" : MODEL,
+          "skin" : SKIN,
+          "frame": FRAME,
+            "scale": SCALE_EXPRESSION
+        }
+

The placeholders MODEL, SKIN, FRAME and SCALE_EXPRESSION have the following meaning

+ + + + + + + + + + + + + + + + + + + + + + + + + +
PlaceholderDescription
MODELThe path to the model file relative to the game path, with an optional colon at the beginning. Mandatory.
SKINThe 0-based index of the skin to display. Optional, defaults to 0.
FRAMEThe 0-based index of the frame to display. Optional, defaults to 0.
SCALE_EXPRESSIONAn expression that is evaluated against an entities’ properties to determine the model scale.
+

If the expression evaluates to a value of type string, then that is interpreted as a map containing only a path key with the string as its value. In other words, if the expression evaluates to a string, then that value is interpreted as the path to a model. Think of such expressions as shorthands that allow you to define a simple model like so:

+
model("path/to/model")
+

instead of having to write

+
model({ "path": "path/to/model" })
+

If the model expression has a scale expression, then its result is used as the scale value for the model. If the expression cannot be evaluated, or if no such expression is given, then the default scale expression from the game configuration is evaluated instead. Refer to this section for more information about SCALE_EXPRESSION and the default scale expression.

+

Basic Examples

+

So a valid model definitions might look like this:

+
// use the model found at the given path with skin 0 and frame 0
+        model("progs/armor")
+
+        // use the model found at the given path with skin 1 and frame 0
+        model({
+          "path": "progs/armor",
+          "skin": 1
+        })
+
+        // use the model found at the given path with skin 1 and frame 3
+        model({
+          "path" : "progs/armor",
+          "skin" : 1,
+          "frame": 3
+        })
+
+        // set a fixed uniform model scale factor 2
+        model({
+          "path" : "progs/armor",
+          "scale" : 2
+        })
+

Sometimes, the actual model that is displayed in game depends on the value of an entity property. TrenchBroom allows you to mimic this behavior by using conditional expressions using the switch and case operators and by referring to the entity properties as variables in the expressions. Let’s look at an example where we combine several model definitions using a literal value.

+
model({{
+          dangle == "1" -> { "path": "progs/voreling.mdl", "skin": 0, "frame": 13 },
+                          { "path": "progs/voreling.mdl" }
+        }})
+

The voreling has two states, either as a normal monster, standing on the ground, or hanging from the ceiling. The model expression contains a switch expression (note the double braces) that comprises of a case expression (note the arrow operator) and a literal map expression. You can interpret this expression as follows:

+
dangle == "1"                                             // If the value of property 'dangle' equals "1"
+        ->                                                        // then
+        { "path": "progs/voreling.mdl", "skin": 0, "frame": 13 }  // use this as the model.
+        ,                                                         // Otherwise,
+        { "path": "progs/voreling.mdl" }                          // use this as the model.
+

If you have problems understanding this syntax, you should read the section on TrenchBroom’s expression language.

+

The following example shows a combination of model definitions using flag values.

+
model({{
+          spawnflags == 2 -> "maps/b_bh100.bsp",
+          spawnflags == 1 -> "maps/b_bh10.bsp",
+                             "maps/b_bh25.bsp"
+        }})
+

As you can see, there are three models attached to the Health kit, maps/b_bh25.bsp, maps/b_bh10.bsp and maps/b_bh100.bsp. This is because the Health kit uses three different models depending on what spawnflags are checked. If ROTTEN is checked, it uses maps/b_bh10.bsp, which is the dim (rotten) health kit and if MEGAHEALTH is checked, then it uses maps/b_bh100.bsp which is the megahealth powerup. If neither are checked, it uses the standard health kit.

+

Accordingly, the nested case expressions inspect the value of the spawnflags property to determine the correct model. Since there is no need to specify a skin or a frame for these models, the expressions only return strings as a shorthand.

+

In the previous example, note that if both ROTTEN and MEGAHEALTH were checked, it would display the megahealth model. Remember that the switch operator returns the value of the first expression that does not evaluate to undefined. For this reason, you must put model definitions with no condition as the last one in the switch because that will override everything else!

+

Advanced Examples

+

The basic expressions you have seen so far allow you to customize which model, skin and frame TrenchBroom shows depending on the values of an entity’s properties with great flexibility, but the actual paths, skin indices and frame indices are hardcoded in the entity definition file. However, sometimes even this flexibility is not enough, in particular with entities that allow you to place arbitrary models into the map. In such cases, the entity definition file cannot contain the actual model paths and so on. Rather, the model path, skin index and frame index are specified by the mapper using entity properties. Since TrenchBroom provides the values of the entity properties to the model expressions as variables, you can easily cover such cases as well.

+

Remember the structure of the model definition maps:

+
{
+          "path" : MODEL,
+          "skin" : SKIN,
+          "frame": FRAME
+        }
+

So far, we have used hardcoded literals for the values of the map entries like so:

+
model({ "path" : "progs/armor", "skin" : 1, "frame": 3 })
+

However, nothing prevents us from using variables instead of hardcoded literals, thereby referring to the entities properties.

+
model({
+          "path" : PATHKEY,
+          "skin" : SKINKEY,
+          "frame": FRAMEKEY
+        })
+

The placeholders PATHKEY, SKINKEY and FRAMEKEY have the following meaning

+ + + + + + + + + + + + + + + + + + + + + +
PlaceholderDescription
PATHKEYThe name of the entity property key in which the model path is stored.
SKINKEYThe name of the entity property key in which the model skin index is stored. Optional.
FRAMEKEYThe name of the entity property key in which the model frame index is stored. Optional.
+

A valid dynamic model definition might look like this:

+
model({
+          "path" : mdl,
+          "skin" : skin,
+          "frame": frame
+        })
+

Then, if you create an entity with the appropriate classname and specifies three properties as follows

+
{
+          "classname" "mydynamicmodelentity"
+          "mdl" "progs/armor.mdl"
+          "skin" "2"
+          "frame" "1"
+        }
+

TrenchBroom will display the second frame of the progs/armor.mdl model using its third skin. If you change these values, the model will be updated in the 3D and 2D viewports accordingly.

+

Differences Between DEF, FGD and ENT Files

+

In both files, the model definitions are just specified alongside with other entity property definitions (note the semicolon after the model definition – this is only necessary in DEF files). An example from a DEF file might look as follows.

+
/*QUAKED item_health (.3 .3 1) (0 0 0) (32 32 32) ROTTEN MEGAHEALTH
+        {
+          model({{ spawnflags == 2 -> "maps/b_bh100.bsp", spawnflags == 1 -> "maps/b_bh10.bsp", "maps/b_bh25.bsp" }});
+        }
+        Health box. Normally gives 25 points.
+
+        Flags:
+        "rotten"
+        gives 15 points
+        "megahealth"
+        will add 100 health, then rot you down to your maximum health limit
+        one point per second
+        */
+

An example from an FGD file might look as follows.

+
@PointClass base(Monster) size(-32 -32 -24, 32 32 64)
+                    model({{ perch == "1" -> "progs/gaunt.mdl", { "path": "progs/gaunt.mdl", "skin": 0, "frame": 24 } }})
+                    = monster_gaunt : "Gaunt"
+        [
+          perch(choices) : "Starting pose" : 0 =
+          [
+            0 : "Flying"
+            1 : "On ground"
+          ]
+        ]
+

To improve compatibility to other editors, the model definition can also be named studio or studioprop in FGD files.

+

In an ENT file, the same model specification might look like this.

+
<point name="ammo_bfg" color=".3 .3 1"
+               box="-16 -16 -16 16 16 16"
+               model="{{ perch == '1' -> 'progs/gaunt.mdl', { 'path': 'progs/gaunt.mdl', 'skin': 0, 'frame': 24 } }}"
+        />
+

Point Files and Portal Files

+

TrenchBroom can load point files (PTS) generated by QBSP, which help locate leaks. After you open a point file with , it’s rendered as a sequence of green line segments which will connect the map interior to the void. Hit to move the camera to the first point, and continue hitting to fly along the path, which should show you where the leak is.

+

Portal files (PRT), also generated by QBSP, let you visualize the portals between BSP leafs. They can be loaded with and are rendered as translucent red polygons.

+

Game Configuration Files

+

TrenchBroom uses game configuration files to provide support for different games. Some game configuration files come with the editor. They are installed at <ResourcePath>/games, where the value of <ResourcePath> depends on the platform according to the following table.

+ + + + + + + + + + + + + + + + + + + + + +
PlatformLocation
WindowsThe directory where the TrenchBroom executable is located.
macOSTrenchBroom.app/Contents/Resources
Linux<prefix>/share/trenchbroom, where <prefix> is the installation prefix.
+

The folder <ResourcePath>/games contains a .cfg file for each supported game, and additional folders which can contain additional resources related to the game such as icons, palettes or entity definition files.

+

It is not recommended to change these builtin game configurations, as they will be overwritten when an update is installed. To modify the existing game configurations or to add new configurations, you can place them in the folder <UserDataPath>/games, where the value of <UserDataPath> is again platform dependent.

+ + + + + + + + + + + + + + + + + + + + + +
PlatformLocation
WindowsC:\Users\<username>\AppData\Roaming\TrenchBroom
macOS~/Library/Application Support/TrenchBroom
Linux~/.TrenchBroom
+

Running TrenchBroom with the --portable argument will instead put the <UserDataPath> in the current directory. This is intended to be run from within the <ResourcePath> directory to provide a fully self-contained instance of the application.

+

To add a new game configuration to TrenchBroom, place it into a folder under <UserDataPath>/games – note that you might need to create that folder if it does not exist. You will need to write your own GameConfig.cfg file, or you can copy one of the builtin files and base your game configuration on that. Additionally, you can place additional resources in the folder you created. As an example, suppose you want to add a game configuration for a game called “Example”. For this, you would create a new folder <UserDataPath>/games/Example, and within that folder, you would create a game configuration file called GameConfig.cfg. If you need additional resource such as an icon or entity definition files, you would place those files into this newly created folder as well.

+

You can also access this directory using the folder icon button below the game list in the game configuration dialog.

+

To override a builtin game configuration file, copy the folder containing the builtin file and place it in <UserDataPath>/games. TrenchBroom will prioritize your custom game configurations over the builtin files, but you can still access the resources in the game’s resource sub folder without problems. If you wish, you can also override some of these resources by placing a file of the same name in your game resource sub directory.

+

As an example, consider the case where you want to override the builtin Quake game configuration and the builtin entity definition file for Quake. Copy the file <ResourcePath>/games/Quake/GameConfig.cfg to <UserDataPath>/games/Quake and modify it as needed. Then copy the file <ResourcePath>/games/Quake/Quake.fgd to <UserDataPath>/games/Quake and modify it, too. When you load the game configuration in TrenchBroom, the editor will pick up the modified files instead of the builtin ones.

+

Game Configuration File Syntax

+

Game configuration files need to specify the following information.

+
    +
  • A name used show in the UI and used to find resources in a sub folder of the game configuration folders
  • +
  • An icon to show in the UI (optional)
  • +
  • File formats to identify which map file formats to support for this game
  • +
  • A Filesystem to specify the game asset search paths and package file format (e.g. pak files)
  • +
  • Textures +
      +
    • A list of file extensions such as .jpg
    • +
    • A palette file (optional)
    • +
    • The worldspawn property to store the texture packages in the map file
    • +
    • A list of exclusion patterns to hide textures matching any of these patterns.
    • +
  • +
  • Entities +
      +
    • The builtin entity definition files
    • +
    • The default color to use in the UI
    • +
    • A default model scale expression
    • +
    • Whether to automatically set default entity properties
    • +
  • +
  • Tags to attach additional information to faces or brushes in the editor, e.g. whether a face is detail or hint. (optional)
  • +
  • Face attributes to specify which additional attributes to allow on brush faces (optional)
  • +
  • Map bounds to be displayed in the 2D viewports (optional)
  • +
  • Compilation tools that can have their paths configured by the user (optional)
  • +
+

The game configuration is an expression language map with a specific structure, which is explained using an example.

+
{
+          "version": 4, // mandatory, indicates the version of the file's syntax
+          "name": "Example Resembling Quake 2", // mandatory, the name to use in the UI
+          "icon": "Icon.png", // optional, the icon to show in the UI
+          "fileformats": [ // supported file formats, each with optional initial map to use as "new map"
+            { "format": "Quake2" },
+            { "format": "Quake2 (Valve)", "initialmap": "initial_valve.map" }
+          ],
+          "filesystem": { // defines the file system used to search for game assets
+            "searchpath": "baseq2", // the path in the game folder at which to search for assets
+            "packageformat": { "extension": ".pak", "format": "idpak" } // the package file format
+          },
+          "textures": { // where to search for textures and how to read them, see below
+            "root": "textures",
+            "extensions": [ ".wal" ],
+            "palette": "pics/colormap.pcx",
+          },
+          "entities": { // the builtin entity definition files for this game
+            "definitions": [ "Quake2.fgd" ],
+            "defaultcolor": "0.6 0.6 0.6 1.0",
+            "scale": [ modelscale, modelscale_vec ]
+          },
+          "tags": { // "smart tags" select or modify a brush/face based on its characteristics
+            "brush": [
+              {
+                "name": "Trigger",
+                "attribs": [ "transparent" ],
+                "match": "classname",
+                "pattern": "trigger*",
+                "texture": "trigger"
+              }
+            ],
+            "brushface": [
+              {
+                "name": "Clip",
+                "attribs": [ "transparent" ],
+                "match": "texture",
+                "pattern": "clip"
+              },
+              {
+                "name": "Liquid",
+                "match": "contentflag",
+                "flags": [ "lava", "water" ]
+              },
+              {
+                "name": "Transparent",
+                "attribs": [ "transparent" ],
+                "match": "surfaceflag",
+                "flags": [ "trans33" ]
+              }
+            ]
+          },
+          "faceattribs": { // bitflags assigned to a face to affect its behavior
+            "surfaceflags": [
+              {
+                "name": "light",
+                "description": "Emit light from the surface, brightness is specified in the 'value' field"
+              },
+              {
+                "name": "trans33",
+                "description": "The surface is 33% transparent"
+              },
+              {
+                "name": "hint",
+                "description": "Make a primary bsp splitter"
+              }
+            ],
+            "contentflags": [
+              {
+                "name": "solid",
+                "description": "Default for all brushes"
+              },
+              {
+                "name": "lava",
+                "description": "The brush is lava"
+              },
+              {
+                "unused": true
+              },
+              {
+                "name": "water",
+                "description": "The brush is water"
+              }
+            ]
+          },
+          "softMapBounds":"-4096 -4096 -4096 4096 4096 4096",
+          "compilationTools": [
+            { "name": "bsp" },
+            { "name": "vis" },
+            { "name": "rad" }
+          ]
+        }
+

Versions

+

The game configuration files are versioned. Whenever a breaking change to the game configuration format is introduced, the version number will increase and TrenchBroom will reject the old format with an error message.

+

Current Versions

+

TrenchBroom currently supports game config version 9.

+

Version History

+
    +
  • Version 9 +
      +
    • Adapt to terminology change: texture renamed to material
    • +
  • +
  • Version 8 +
      +
    • Remove texture format configuration and just keep a list of extensions to search for.
    • +
  • +
  • Version 7 +
      +
    • Replace texture package configuration with a root path. Removes the distinction between file and directory based texture configurations.
    • +
  • +
  • Version 6 +
      +
    • Adds the optional setDefaultProperties key to the entity configuration.
    • +
  • +
  • Version 5 +
      +
    • Makes the model format whitelist optional. If a whitelist is still present in a config file, it is ignored.
    • +
  • +
  • Version 4 +
      +
    • Adds support for the unused key in surface flags and content flags; this key does not exist in version 3.
    • +
    • Adds support for specifying a list of values for the pattern key in surfaceparm-type smart tags; in version 3 only a single value is allowed.
    • +
    • Adds the optional softMapBounds key.
    • +
    • Adds the optional compilationTools key.
    • +
  • +
+

Migrating from Version 2

+

Version 3 deprecated the brushtypes key in favor of the tags key, but the contents are very similar. The value of the brushtypes key is an array of type matchers. The following brush type matchers are supported in version 2:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MatchDescription
materialMatch against a material name, must match all brush faces
contentflagMatch against face content flags (used by Quake 2, Quake 3)
surfaceflagMatch against face surface flags (used by Quake 2)
surfaceparmMatch against shader surface parameters (used by Quake 3)
classnameMatch against a brush entity class name
+

File Formats

+

The file format is specified by an array of maps under the key fileformats. The following formats are supported.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FormatDescription
StandardStandard Quake map file
ValveValve map file (like Standard, but with more control over UV mapping)
Quake2Quake 2 map file with Standard style texture info
Quake2 (Valve)Quake 2 map file with Valve style texture info
Quake3 (legacy)Quake 3 map file with Standard style texture info
Quake3 (Valve)Quake 3 map file with Valve style texture info
Hexen2Hexen 2 map file (like Quake, but with an additional, but unused value per face)
+

Note that the “Quake3” format, which will include Quake 3 brush primitives support, is not yet fully implemented and so is omitted from the list above. The “Quake3 (Valve)” format is as expressive for texture placement as the brush primitives format, but “Quake3 (Valve)” cannot be used to read existing map files that contain brush primitives. Also note that none of the Quake 3 formats yet support patch meshes.

+

Each entry of the array must have the following structure:

+
{
+          "format": "Standard",
+          "initialmap: "initial_standard.map"
+        }
+

Thereby, the format key is mandatory but the initialmap key is optional. The initialmap key refers to a map file in the game’s configuration sub folder which should be loaded if a new document is created. If no initial map is specified, or if the file cannot be found, TrenchBroom will create a map containing a single brush at the origin.

+

File System

+

The file system is used in the editor to load game assets, and it is specified by a map under the key filesystem. The map contains two keys, searchpath and packageformat.

+
    +
  • searchpath is the subdirectory under the game directory (set in the game preferences) at which the editor will search for game assets. The editor will search loose files in this path, but it will also mount packages found here.
  • +
  • packageformat specifies the format of the packages to mount. It is a map with two keys, extension and format. +
      +
    • extensions specifies the file extensions of the package files to mount (alternatively allows extension to specify only one extension)
    • +
    • format specifies the format of the package files
    • +
  • +
+

The following package formats are supported.

+ + + + + + + + + + + + + + + + + + + + + +
FormatDescription
idpakId pak file
dkpakDaikatana pak file
zipZip file, often uses other extensions such as pk3
+

Material Configurations

+

Every material configuration consists of a root search directory, and optionally a list of included file extensions, a palette path, an attribute for wad file lists and a list of exclusion patterns.

+
"materials": {
+          "root": "textures",
+          "extensions": [ ".D" ],
+          "palette": "pics/colormap.pcx",
+          "attribute": "wad",
+          "excludes": [ "*_norm", "*_gloss" ],
+        },
+

The root key specifies the folder at which to search for the material packages. This folder is relative to the game file system set up according to the filesystem configuration earlier in the file. TrenchBroom will create a material collection for each folder contained in the root folder specified here.

+

In the case of Quake 2, the builtin game configuration specifies the search path of the file system as "baseq2" and the material package root as "textures", so TrenchBroom will create a material collection for each folder found in <Game Path>/baseq2/textures.

+

TrenchBroom supports a wide array of image formats such as tga, pcx, jpeg, and so on. TrenchBroom uses the FreeImage Library to load these images and supports any file type supported by this library.

+

Optionally, you can specify a palette. The value of the palette key specifies a path, relative to the file system, where TrenchBroom will look for a palette file that comes with the game’s assets.

+

The attribute key specifies the name of a worldspawn property where TrenchBroom will store the wad files in the map file.

+

The optional excludes key specifies a list of patterns matched against material names which will be ignored and not displayed in the material browser. Wildcards * and ? are allowed. Use backslashes to escape literal * and ? chars.

+
"materials": {
+          "root": "textures",
+          "extensions": [ "" ],
+          "excludes": [ "*_norm", "*_gloss" ]
+        },
+

Entity Configuration

+

In the entity configuration section, you can specify which entity definition files come with your game configuration, a default color for entities and an expression that yields a default scale when evaluated against an entities’ properties.

+
"entities": { // the builtin entity definition files for this game
+        "definitions": [ "Quake2/Quake2.fgd" ],
+          "defaultcolor": "0.6 0.6 0.6 1.0",
+          "scale": [ modelscale, modelscale_vec ],
+          "setDefaultProperties": true
+        },
+

The definitions key provides a list of entity definition files. These files are specified by a path that is relative to the games directory where TrenchBroom searches for the game configurations.

+

The scale key has an expression that is evaluated against an entities’ properties to determine the model scale. This expression can refer to any of the entities’ properties, or it can provide fixed values.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ExampleDescription
"scale": 2A fixed uniform scale factor of 2.
"scale": "1 2 3"A fixed non-uniform scale factor scaling X by 1, Y by 2 and Z by 3.
"scale": modelscaleUse the value of the entities’ modelscale property.
"scale": [ modelscale, modelscale_vec ]Try the individual values in the array until we find one that doesn’t evaluate to Undefined or Null.
+

Of course, you could use the switch and case operators for more complicated cases.

+

The optional setDefaultProperties key controls whether default entity properties are instantiated automatically when TrenchBroom creates a new entity. Defaults to false if not set.

+

Tags

+

TrenchBroom can recognize certain special brush or face types. An example would be clip faces or trigger brushes. But since the details can be game dependent, these special types are defined in the game configuration. For greater flexibility and future enhancements, a general “smart tags” system is used to realize this functionality.

+

TrenchBroom uses these tag definitions to automatically apply attributes to matching brushes/faces — for example to render trigger brushes partially transparent — and to populate the filtering options available in the View menu.

+

Each smart tag definition also makes one or more related keyboard shortcuts available (searching the shortcuts by “Tags” will show all of these). Each tag will always have a related shortcut that can be used to toggle the visibility of brushes whose faces match the tag. Additional shortcuts may also be available to apply the characteristics of the tag to the current selection, or remove those characteristics. These shortcuts depend on the tag’s match criteria as described below.

+

The tags are specified separately for brushes and faces under the corresponding keys:

+
"tags": {
+          "brush": [ ... ],
+          "brushface": [ ... ]
+        }
+

Each of these keys has a list of tags. Each tag looks as follows.

+
{
+          "name": "Clip",
+          "attribs": [ "transparent" ],
+          "match": "material",
+          "pattern": "clip"
+        },
+

The only attribute type currently supported in the attribs list is “transparent”, which as mentioned above will cause faces matching this tag to be rendered with partial transparency in the 3D viewport.

+

The match key specifies how TrenchBroom will determine whether or not this tag applies to a brush or face.

+

For a brush smart tag, the match key can only have the “classname” value. In addition to the usual keyboard shortcut for view filtering, this kind of smart tag will also generate keyboard shortcuts to either apply the tag (create a brush entity from selected brushes) or remove it (return selected brushes to worldspawn). This can be summarized as follows:

+ + + + + + + + + + + + + + + + + +
MatchDescriptionShortcut to applyShortcut to remove
classnameMatch against brush entity class nameYesYes
+

For a brushface smart tag, the match key can have the following values and will generate keyboard shortcuts to apply or remove the match criteria on selected faces accordingly:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MatchDescriptionShortcut to applyShortcut to remove
materialMatch against a material nameYesNo
contentflagMatch against face content flagsYesYes
surfaceflagMatch against face surface flagsYesYes
surfaceparmMatch against shader surface parameterYesNo
+

Additional keys will be required to configure the matcher, depending on the value of the match key.

+
    +
  • For the classname matcher, the key pattern contains a pattern that is matched against the classname of the brush entity that contains the brush. Wildcards * and ? are allowed. Use backslashes to escape literal * and ? chars. +
      +
    • Additionally, the classname matcher can contain an optional material key. When this tag is applied by the use of its keyboard shortcut, then the selected brushes will receive the material with the name given as the value of this key (e.g. "material": "trigger" will assign the trigger material).
    • +
  • +
  • For the material matcher, the key pattern contains a pattern that is matched against a face’s material name. If the pattern does not contain a slash, it will only be matched against the segment after the final slash (if any) in the material name. Wildcards * and ? are allowed. Use backslashes to escape literal * and ? chars.
  • +
  • For the contentflag and surfaceflag matchers, the key flags contains a list of content or surface flag names to match against (see below for more info on content and surface flags).
  • +
  • For the surfaceparm matcher, the key pattern contains a name that is matched against the surface parameters of a face’s shader. No wildcards allowed; the parameter name must match exactly. In version 4 of the game config format, you may alternately specify a list of surfaceparm names for this value, which will match against a shader if it has any of those surfaceparms.
  • +
+

Face Attributes

+

The main part of the faceattribs object is the set of definitions of available surface flags (generally affecting the appearance/behavior of an individual face) and content flags (generally affecting the behavior of the brush containing the face). These definitions are specified through the surfaceflags and contentflags keys.

+

The value for each of those keys is a list of flag definitions. Note that the position of each flag definition within its list determines the value of that flag. Suppose that i is the 0-based list index of a flag; that flag’s value then corresponds to 2 to the power of i. The first flag in the list has value 2^0 = 1, the second has value 2^1 = 2, the third has value 2^2 = 4, and so on.

+

Consider the following example:

+
"faceattribs": {
+          "surfaceflags": [
+            {
+              "name": "light",
+              "description": "Emit light from the surface, brightness is specified in the 'value' field"
+            }, // value 1
+            {
+              "name": "slick",
+              "description": "The surface is slippery"
+            } // value 2
+          ],
+          "contentflags": [
+            {
+              "name": "solid",
+              "description": "Default for all brushes"
+            }, // value 1
+            {
+              "name": "window",
+              "description": "Brush is a window (not really used)"
+            }, // value 2
+            {
+              "unused": true
+            }, // value 4
+            {
+              "name": "playerclip",
+              "description": "Player cannot pass through the brush (other things can)"
+            }, // value 8
+          ]
+        }
+

There are two surface flags with values 1 and 2, and three valid content flags with values 1, 2, and 8. Note that the third element in the contentflags list, marked as unused, is just a placeholder. This is necessary so that the next flag, “playerclip”, receives the correct value of 8.

+

For any flag definition not marked as unused, the name key is mandatory and the description key is optional. The name value will appear in the flag editor UI, and the description (if provided) will be visible in a tooltip when hovering over a flag checkbox.

+

Note that before version 4 of the game config format, the unused key is not available for flag definitions. You can still effectively skip unused flag values in version 3 with placeholder flag definitions that by convention simply have the name “unused”, for example the third element in the contentflags list above could instead be

+
{
+          "name": "unused"
+        }, // value 4
+

This approach will however cause flags named “unused” to appear in the flag editor UI.

+

The faceattribs object may contain one other key, defaults. The value of this key is an object that defines the initial values seen in the face attribute editor for the face of a newly created brush. The following defaults keys are supported:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDescription
offsetList of two numbers specifying the default X and Y offset
scaleList of two numbers specifying the default X and Y scale
rotationNumber specifying the default rotation angle
surfaceValueNumber specifying the default surface value (only applicable if surfaceflags exist)
surfaceFlagsList of strings naming the default surface flags
surfaceContentsList of strings naming the default content flags
colorString specifying the default surface color (only applicable for Daikatana)
+

List values must be given in array format, e.g. a default scale of 0.5 along each axis would be specified within the defaults object as: "scale": [0.5, 0.5]

+

The flag names specified for surfaceFlags or surfaceContents must correspond to the name value for existing flags defined in the surfaceflags or contentflags (respectively) of the faceattribs object.

+

The color value must be a string of the form “R G B” or “R G B A”. R G B and A are each a floating-point number from 0.0 to 1.0. If A is omitted it is assumed to be 1.0.

+

Map Bounds

+

The optional softMapBounds key defines the default map bounds to draw in the 2D viewports. Its value is a string that contains the coordinates of two opposite points that define the volume enclosed by the bounds. The example here defines a cube from the point (-4096, -4096, -4096) to the point (4096, 4096, 4096):

+
"softMapBounds":"-4096 -4096 -4096 4096 4096 4096",
+

Compilation Tools

+

The optional compilationTools list identifies tool names that will appear in the game configuration dialog, allowing the user to associate these names with paths to tool executables. Such a name can be used as a variable in this game’s compilation profiles to represent the associated path.

+

Each element in the list is an object that must have a name key and may optionally have a description key (used for tooltips). An example from the Quake 3 game configuration that defines two tools:

+
"compilationTools": [
+          { "name": "q3map2", "description": "Path to your q3map2 executable, which performs the main bsp/vis/light compilation phases" },
+          { "name": "bspc", "description": "Path to your bspc or mbspc executable, which creates .aas files for bot support" }
+        ]
+

Getting Involved

+

Suggesting a Feature

+

If you have an idea for a nice feature that you’re missing in TrenchBroom, then you can submit a request at the TrenchBroom issue tracker. Try to describe your feature, but don’t go into too much detail. If it gets picked up, we will hash out the details together.

+

Reporting Bugs

+

You can submit bug reports at the TrenchBroom issue tracker. Be sure to include the the following information:

+
    +
  • TrenchBroom version: e.g., "*“Version 2.0.0 f335082 D” see below
  • +
  • Operation system and version: e.g. “Windows 7 64bit”
  • +
  • Crash report and the map file: When TrenchBroom crashes, it saves a crash report and the map file automatically. These files are placed in the folder containing the current map file, or in your documents folder if the current map hasn’t been saved yet. For example, if the map file you are editing has the name “rtz_q1.map”, the crash report will be named “rtz_q1-crash.txt”, and the saved map file will be named “rtz_q1-crash.map”. Existing files are not overwritten - TrenchBroom creates new file names by attaching a number at the end. Please choose the files with the highest numbers when reporting a bug.
  • +
  • Exact steps to reproduce: It is really helpful if you can provide exact info on how to reproduce the problem. Sometimes this can be difficult to describe, so you can attach screenshots or make screencasts if necessary. If you cannot reproduce the problem, please submit a bug report either way. The cause of the problem can often be deduced anyway.
  • +
+

The Version Information

+

Open the “About TrenchBroom” dialog from the menu. The light gray text on the left gives you some information about which version of TrenchBroom you are currently running, for example “Version 2.0.0 f335082 D”. The first three numbers represent the version (2.0.0), the following seven letter string is the build id (f335082), and the final letter indicates the build type (“D” for Debug and “R” for release). You can also find this information in the Welcome window that the editor shows at startup.

+

If you click on the version information strings, they will be copied to the clipboard, which is useful for bug reports.

+

Contact

+ +

References and Links

+ +
+ +
+ + diff --git a/tools/trenchbroom/manual/shortcuts.js b/tools/trenchbroom/manual/shortcuts.js new file mode 100644 index 0000000..41544f8 --- /dev/null +++ b/tools/trenchbroom/manual/shortcuts.js @@ -0,0 +1,394 @@ +const keys = { + 'Esc': 'Esc', + 'Tab': 'Tab', + 'Backtab': 'Backtab', + 'Backspace': 'Backspace', + 'Return': 'Return', + 'Enter': 'Enter', + 'Ins': 'Ins', + 'Del': 'Del', + 'Pause': 'Pause', + 'Print': 'Print', + 'SysReq': 'SysReq', + 'Clear': 'Clear', + 'Home': 'Home', + 'End': 'End', + 'Left': 'Left', + 'Up': 'Up', + 'Right': 'Right', + 'Down': 'Down', + 'PgUp': 'PgUp', + 'PgDown': 'PgDown', + 'Shift': 'Shift', + 'Ctrl': 'Ctrl', + 'Meta': 'Meta', + 'Alt': 'Alt', + 'CapsLock': 'CapsLock', + 'NumLock': 'NumLock', + 'ScrollLock': 'ScrollLock', + 'F1': 'F1', + 'F2': 'F2', + 'F3': 'F3', + 'F4': 'F4', + 'F5': 'F5', + 'F6': 'F6', + 'F7': 'F7', + 'F8': 'F8', + 'F9': 'F9', + 'F10': 'F10', + 'F11': 'F11', + 'F12': 'F12', + 'F13': 'F13', + 'F14': 'F14', + 'F15': 'F15', + 'F16': 'F16', + 'F17': 'F17', + 'F18': 'F18', + 'F19': 'F19', + 'F20': 'F20', + 'F21': 'F21', + 'F22': 'F22', + 'F23': 'F23', + 'F24': 'F24', + 'F25': 'F25', + 'F26': 'F26', + 'F27': 'F27', + 'F28': 'F28', + 'F29': 'F29', + 'F30': 'F30', + 'F31': 'F31', + 'F32': 'F32', + 'F33': 'F33', + 'F34': 'F34', + 'F35': 'F35', + 'ៀ?': 'ៀ?', + 'ៀ?': 'ៀ?', + 'Menu': 'Menu', + 'ៀ?': 'ៀ?', + 'ៀ?': 'ៀ?', + 'Help': 'Help', + 'ៀ?': 'ៀ?', + 'ៀ?': 'ៀ?', + 'Space': 'Space', + 'Space': 'Space', + '!': '!', + '"': '"', + '#': '#', + '$': '$', + '%': '%', + '&': '&', + '\'': '\'', + '(': '(', + ')': ')', + '*': '*', + '+': '+', + ',': ',', + '-': '-', + '.': '.', + '/': '/', + '0': '0', + '1': '1', + '2': '2', + '3': '3', + '4': '4', + '5': '5', + '6': '6', + '7': '7', + '8': '8', + '9': '9', + ':': ':', + ';': ';', + '<': '<', + '=': '=', + '>': '>', + '?': '?', + '@': '@', + 'A': 'A', + 'B': 'B', + 'C': 'C', + 'D': 'D', + 'E': 'E', + 'F': 'F', + 'G': 'G', + 'H': 'H', + 'I': 'I', + 'J': 'J', + 'K': 'K', + 'L': 'L', + 'M': 'M', + 'N': 'N', + 'O': 'O', + 'P': 'P', + 'Q': 'Q', + 'R': 'R', + 'S': 'S', + 'T': 'T', + 'U': 'U', + 'V': 'V', + 'W': 'W', + 'X': 'X', + 'Y': 'Y', + 'Z': 'Z', + '[': '[', + '\\': '\\', + ']': ']', + '^': '^', + '_': '_', + '`': '`', + '{': '{', + '|': '|', + '}': '}', + '~': '~', + ' ': ' ', + '¡': '¡', + '¢': '¢', + '£': '£', + '¤': '¤', + '¥': '¥', + '¦': '¦', + '§': '§', + '¨': '¨', + '©': '©', + 'ª': 'ª', + '«': '«', + '¬': '¬', + '­': '­', + '®': '®', + '¯': '¯', + '°': '°', + '±': '±', + '²': '²', + '³': '³', + '´': '´', + 'Μ': 'Μ', + '¶': '¶', + '·': '·', + '¸': '¸', + '¹': '¹', + 'º': 'º', + '»': '»', + '¼': '¼', + '½': '½', + '¾': '¾', + '¿': '¿', + 'À': 'À', + 'Á': 'Á', + 'Â': 'Â', + 'Ã': 'Ã', + 'Ä': 'Ä', + 'Å': 'Å', + 'Æ': 'Æ', + 'Ç': 'Ç', + 'È': 'È', + 'É': 'É', + 'Ê': 'Ê', + 'Ë': 'Ë', + 'Ì': 'Ì', + 'Í': 'Í', + 'Î': 'Î', + 'Ï': 'Ï', + 'Ð': 'Ð', + 'Ñ': 'Ñ', + 'Ò': 'Ò', + 'Ó': 'Ó', + 'Ô': 'Ô', + 'Õ': 'Õ', + 'Ö': 'Ö', + '×': '×', + 'Ø': 'Ø', + 'Ù': 'Ù', + 'Ú': 'Ú', + 'Û': 'Û', + 'Ü': 'Ü', + 'Ý': 'Ý', + 'Þ': 'Þ', + 'ß': 'ß', + '÷': '÷', + 'Ÿ': 'Ÿ', +}; +const menu = { + 'Menu/File/New': { path: ['File', 'New Document'], shortcut: { key: 'N', modifiers: ['Ctrl', ] } }, + 'Menu/File/Open...': { path: ['File', 'Open Document...'], shortcut: { key: 'O', modifiers: ['Ctrl', ] } }, + 'Menu/File/Save': { path: ['File', 'Save Document'], shortcut: { key: 'S', modifiers: ['Ctrl', ] } }, + 'Menu/File/Save as...': { path: ['File', 'Save Document as...'], shortcut: { key: '', modifiers: [] } }, + 'Menu/File/Export/Wavefront OBJ...': { path: ['File', 'Export', 'Wavefront OBJ...'], shortcut: { key: '', modifiers: [] } }, + 'Menu/File/Export/Map...': { path: ['File', 'Export', 'Map...'], shortcut: { key: '', modifiers: [] } }, + 'Menu/File/Load Point File...': { path: ['File', 'Load Point File...'], shortcut: { key: '', modifiers: [] } }, + 'Menu/File/Reload Point File': { path: ['File', 'Reload Point File'], shortcut: { key: '', modifiers: [] } }, + 'Menu/File/Unload Point File': { path: ['File', 'Unload Point File'], shortcut: { key: '', modifiers: [] } }, + 'Menu/File/Load Portal File...': { path: ['File', 'Load Portal File...'], shortcut: { key: '', modifiers: [] } }, + 'Menu/File/Reload Portal File': { path: ['File', 'Reload Portal File'], shortcut: { key: '', modifiers: [] } }, + 'Menu/File/Unload Portal File': { path: ['File', 'Unload Portal File'], shortcut: { key: '', modifiers: [] } }, + 'Menu/File/Reload Texture Collections': { path: ['File', 'Reload Texture Collections'], shortcut: { key: 'F5', modifiers: [] } }, + 'Menu/File/Reload Entity Definitions': { path: ['File', 'Reload Entity Definitions'], shortcut: { key: 'F6', modifiers: [] } }, + 'Menu/File/Revert': { path: ['File', 'Revert Document'], shortcut: { key: '', modifiers: [] } }, + 'Menu/File/Close': { path: ['File', 'Close Document'], shortcut: { key: 'F4', modifiers: ['Ctrl', ] } }, + 'Menu/Edit/Undo': { path: ['Edit', 'Undo'], shortcut: { key: 'Z', modifiers: ['Ctrl', ] } }, + 'Menu/Edit/Redo': { path: ['Edit', 'Redo'], shortcut: { key: 'Y', modifiers: ['Ctrl', ] } }, + 'Menu/Edit/Repeat': { path: ['Edit', 'Repeat Last Commands'], shortcut: { key: 'R', modifiers: ['Ctrl', ] } }, + 'Menu/Edit/Clear Repeatable Commands': { path: ['Edit', 'Clear Repeatable Commands'], shortcut: { key: 'R', modifiers: ['Ctrl', 'Shift', ] } }, + 'Menu/Edit/Cut': { path: ['Edit', 'Cut'], shortcut: { key: 'X', modifiers: ['Ctrl', ] } }, + 'Menu/Edit/Copy': { path: ['Edit', 'Copy'], shortcut: { key: 'C', modifiers: ['Ctrl', ] } }, + 'Menu/Edit/Paste': { path: ['Edit', 'Paste'], shortcut: { key: 'V', modifiers: ['Ctrl', ] } }, + 'Menu/Edit/Paste at Original Position': { path: ['Edit', 'Paste at Original Position'], shortcut: { key: 'V', modifiers: ['Ctrl', 'Alt', ] } }, + 'Menu/Edit/Duplicate': { path: ['Edit', 'Duplicate'], shortcut: { key: 'D', modifiers: ['Ctrl', ] } }, + 'Menu/Edit/Delete': { path: ['Edit', 'Delete'], shortcut: { key: 'Del', modifiers: [] } }, + 'Menu/Edit/Select All': { path: ['Edit', 'Select All'], shortcut: { key: 'A', modifiers: ['Ctrl', ] } }, + 'Menu/Edit/Select Siblings': { path: ['Edit', 'Select Siblings'], shortcut: { key: 'B', modifiers: ['Ctrl', ] } }, + 'Menu/Edit/Select Touching': { path: ['Edit', 'Select Touching'], shortcut: { key: 'T', modifiers: ['Ctrl', ] } }, + 'Menu/Edit/Select Inside': { path: ['Edit', 'Select Inside'], shortcut: { key: 'E', modifiers: ['Ctrl', ] } }, + 'Menu/Edit/Select Tall': { path: ['Edit', 'Select Tall'], shortcut: { key: 'E', modifiers: ['Ctrl', 'Shift', ] } }, + 'Menu/Edit/Select by Line Number': { path: ['Edit', 'Select by Line Number...'], shortcut: { key: '', modifiers: [] } }, + 'Menu/Edit/Select Inverse': { path: ['Edit', 'Select Inverse'], shortcut: { key: 'A', modifiers: ['Ctrl', 'Alt', ] } }, + 'Menu/Edit/Select None': { path: ['Edit', 'Select None'], shortcut: { key: 'A', modifiers: ['Ctrl', 'Shift', ] } }, + 'Menu/Edit/Group': { path: ['Edit', 'Group Selected Objects'], shortcut: { key: 'G', modifiers: ['Ctrl', ] } }, + 'Menu/Edit/Ungroup': { path: ['Edit', 'Ungroup Selected Objects'], shortcut: { key: 'G', modifiers: ['Ctrl', 'Shift', ] } }, + 'Menu/Edit/Create Linked Duplicate': { path: ['Edit', 'Create Linked Duplicate'], shortcut: { key: 'D', modifiers: ['Ctrl', 'Shift', ] } }, + 'Menu/Edit/Select Linked Groups': { path: ['Edit', 'Select Linked Groups'], shortcut: { key: '', modifiers: [] } }, + 'Menu/Edit/Separate Linked Groups': { path: ['Edit', 'Separate Selected Groups'], shortcut: { key: '', modifiers: [] } }, + 'Menu/Edit/Clear Protected Properties': { path: ['Edit', 'Clear Protected Properties'], shortcut: { key: '', modifiers: [] } }, + 'Controls/Map view/Flip objects horizontally': { path: ['Edit', 'Flip Horizontally'], shortcut: { key: 'F', modifiers: ['Ctrl', ] } }, + 'Controls/Map view/Flip objects vertically': { path: ['Edit', 'Flip Vertically'], shortcut: { key: 'F', modifiers: ['Ctrl', 'Alt', ] } }, + 'Menu/Edit/Move objects': { path: ['Edit', 'Move...'], shortcut: { key: 'M', modifiers: ['Ctrl', 'Alt', ] } }, + 'Menu/Edit/Tools/Brush Tool': { path: ['Edit', 'Tools', 'Brush Tool'], shortcut: { key: 'B', modifiers: [] } }, + 'Menu/Edit/Tools/Clip Tool': { path: ['Edit', 'Tools', 'Clip Tool'], shortcut: { key: 'C', modifiers: [] } }, + 'Menu/Edit/Tools/Rotate Tool': { path: ['Edit', 'Tools', 'Rotate Tool'], shortcut: { key: 'R', modifiers: [] } }, + 'Menu/Edit/Tools/Scale Tool': { path: ['Edit', 'Tools', 'Scale Tool'], shortcut: { key: 'T', modifiers: [] } }, + 'Menu/Edit/Tools/Shear Tool': { path: ['Edit', 'Tools', 'Shear Tool'], shortcut: { key: 'G', modifiers: [] } }, + 'Menu/Edit/Tools/Vertex Tool': { path: ['Edit', 'Tools', 'Vertex Tool'], shortcut: { key: 'V', modifiers: [] } }, + 'Menu/Edit/Tools/Edge Tool': { path: ['Edit', 'Tools', 'Edge Tool'], shortcut: { key: 'E', modifiers: [] } }, + 'Menu/Edit/Tools/Face Tool': { path: ['Edit', 'Tools', 'Face Tool'], shortcut: { key: 'F', modifiers: [] } }, + 'Controls/Map view/Deactivate current tool': { path: ['Edit', 'Tools', 'Deactivate Current Tool'], shortcut: { key: 'Esc', modifiers: ['Shift', ] } }, + 'Menu/Edit/CSG/Convex Merge': { path: ['Edit', 'CSG', 'Convex Merge'], shortcut: { key: 'J', modifiers: ['Ctrl', ] } }, + 'Menu/Edit/CSG/Subtract': { path: ['Edit', 'CSG', 'Subtract'], shortcut: { key: 'K', modifiers: ['Ctrl', ] } }, + 'Menu/Edit/CSG/Hollow': { path: ['Edit', 'CSG', 'Hollow'], shortcut: { key: 'K', modifiers: ['Ctrl', 'Shift', ] } }, + 'Menu/Edit/CSG/Intersect': { path: ['Edit', 'CSG', 'Intersect'], shortcut: { key: 'L', modifiers: ['Ctrl', ] } }, + 'Menu/Edit/Snap Vertices to Integer': { path: ['Edit', 'Snap Vertices to Integer'], shortcut: { key: 'V', modifiers: ['Ctrl', 'Shift', ] } }, + 'Menu/Edit/Snap Vertices to Grid': { path: ['Edit', 'Snap Vertices to Grid'], shortcut: { key: 'V', modifiers: ['Ctrl', 'Alt', 'Shift', ] } }, + 'Menu/Edit/Texture Lock': { path: ['Edit', 'Texture Lock'], shortcut: { key: '', modifiers: [] } }, + 'Menu/Edit/UV Lock': { path: ['Edit', 'UV Lock'], shortcut: { key: 'U', modifiers: [] } }, + 'Menu/Edit/Replace Texture...': { path: ['Edit', 'Replace Texture...'], shortcut: { key: '', modifiers: [] } }, + 'Menu/View/Grid/Show Grid': { path: ['View', 'Grid', 'Show Grid'], shortcut: { key: '0', modifiers: [] } }, + 'Menu/View/Grid/Snap to Grid': { path: ['View', 'Grid', 'Snap to Grid'], shortcut: { key: '0', modifiers: ['Alt', ] } }, + 'Menu/View/Grid/Increase Grid Size': { path: ['View', 'Grid', 'Increase Grid Size'], shortcut: { key: '+', modifiers: [] } }, + 'Menu/View/Grid/Decrease Grid Size': { path: ['View', 'Grid', 'Decrease Grid Size'], shortcut: { key: '-', modifiers: [] } }, + 'Menu/View/Grid/Set Grid Size 0.125': { path: ['View', 'Grid', 'Set Grid Size 0.125'], shortcut: { key: '', modifiers: [] } }, + 'Menu/View/Grid/Set Grid Size 0.25': { path: ['View', 'Grid', 'Set Grid Size 0.25'], shortcut: { key: '', modifiers: [] } }, + 'Menu/View/Grid/Set Grid Size 0.5': { path: ['View', 'Grid', 'Set Grid Size 0.5'], shortcut: { key: '', modifiers: [] } }, + 'Menu/View/Grid/Set Grid Size 1': { path: ['View', 'Grid', 'Set Grid Size 1'], shortcut: { key: '1', modifiers: [] } }, + 'Menu/View/Grid/Set Grid Size 2': { path: ['View', 'Grid', 'Set Grid Size 2'], shortcut: { key: '2', modifiers: [] } }, + 'Menu/View/Grid/Set Grid Size 4': { path: ['View', 'Grid', 'Set Grid Size 4'], shortcut: { key: '3', modifiers: [] } }, + 'Menu/View/Grid/Set Grid Size 8': { path: ['View', 'Grid', 'Set Grid Size 8'], shortcut: { key: '4', modifiers: [] } }, + 'Menu/View/Grid/Set Grid Size 16': { path: ['View', 'Grid', 'Set Grid Size 16'], shortcut: { key: '5', modifiers: [] } }, + 'Menu/View/Grid/Set Grid Size 32': { path: ['View', 'Grid', 'Set Grid Size 32'], shortcut: { key: '6', modifiers: [] } }, + 'Menu/View/Grid/Set Grid Size 64': { path: ['View', 'Grid', 'Set Grid Size 64'], shortcut: { key: '7', modifiers: [] } }, + 'Menu/View/Grid/Set Grid Size 128': { path: ['View', 'Grid', 'Set Grid Size 128'], shortcut: { key: '8', modifiers: [] } }, + 'Menu/View/Grid/Set Grid Size 256': { path: ['View', 'Grid', 'Set Grid Size 256'], shortcut: { key: '9', modifiers: [] } }, + 'Menu/View/Camera/Move to Next Point': { path: ['View', 'Camera', 'Move Camera to Next Point'], shortcut: { key: '.', modifiers: [] } }, + 'Menu/View/Camera/Move to Previous Point': { path: ['View', 'Camera', 'Move Camera to Previous Point'], shortcut: { key: ',', modifiers: [] } }, + 'Menu/View/Camera/Reset 2D Cameras': { path: ['View', 'Camera', 'Reset 2D Cameras'], shortcut: { key: 'U', modifiers: ['Ctrl', 'Shift', ] } }, + 'Menu/View/Camera/Focus on Selection': { path: ['View', 'Camera', 'Focus Camera on Selection'], shortcut: { key: 'U', modifiers: ['Ctrl', ] } }, + 'Menu/View/Camera/Move Camera to...': { path: ['View', 'Camera', 'Move Camera to...'], shortcut: { key: '', modifiers: [] } }, + 'Menu/View/Isolate': { path: ['View', 'Isolate Selection'], shortcut: { key: 'I', modifiers: ['Ctrl', ] } }, + 'Menu/View/Hide': { path: ['View', 'Hide Selection'], shortcut: { key: 'I', modifiers: ['Ctrl', 'Alt', ] } }, + 'Menu/View/Show All': { path: ['View', 'Show All'], shortcut: { key: 'I', modifiers: ['Ctrl', 'Shift', ] } }, + 'Menu/View/Switch to Map Inspector': { path: ['View', 'Show Map Inspector'], shortcut: { key: '1', modifiers: ['Ctrl', ] } }, + 'Menu/View/Switch to Entity Inspector': { path: ['View', 'Show Entity Inspector'], shortcut: { key: '2', modifiers: ['Ctrl', ] } }, + 'Menu/View/Switch to Face Inspector': { path: ['View', 'Show Face Inspector'], shortcut: { key: '3', modifiers: ['Ctrl', ] } }, + 'Menu/View/Toggle Toolbar': { path: ['View', 'Toggle Toolbar'], shortcut: { key: 'T', modifiers: ['Ctrl', 'Alt', ] } }, + 'Menu/View/Toggle Info Panel': { path: ['View', 'Toggle Info Panel'], shortcut: { key: '4', modifiers: ['Ctrl', ] } }, + 'Menu/View/Toggle Inspector': { path: ['View', 'Toggle Inspector'], shortcut: { key: '5', modifiers: ['Ctrl', ] } }, + 'Menu/View/Maximize Current View': { path: ['View', 'Maximize Current View'], shortcut: { key: 'Space', modifiers: ['Ctrl', ] } }, + 'Menu/File/Preferences...': { path: ['View', 'Preferences...'], shortcut: { key: '', modifiers: [] } }, + 'Menu/Run/Compile...': { path: ['Run', 'Compile Map...'], shortcut: { key: '', modifiers: [] } }, + 'Menu/Run/Launch...': { path: ['Run', 'Launch Engine...'], shortcut: { key: '', modifiers: [] } }, + 'Menu/Help/TrenchBroom Manual': { path: ['Help', 'TrenchBroom Manual'], shortcut: { key: 'F1', modifiers: [] } }, + 'Menu/File/About TrenchBroom': { path: ['Help', 'About TrenchBroom'], shortcut: { key: '', modifiers: [] } }, +}; +const actions = { + 'Controls/Map view/Deactivate current tool': { key: 'Esc', modifiers: ['Shift', ] }, + 'Menu/Edit/Tools/Brush Tool': { key: 'B', modifiers: [] }, + 'Menu/Edit/Tools/Clip Tool': { key: 'C', modifiers: [] }, + 'Menu/Edit/Tools/Vertex Tool': { key: 'V', modifiers: [] }, + 'Menu/Edit/Tools/Edge Tool': { key: 'E', modifiers: [] }, + 'Menu/Edit/Tools/Face Tool': { key: 'F', modifiers: [] }, + 'Menu/Edit/Tools/Rotate Tool': { key: 'R', modifiers: [] }, + 'Menu/Edit/Tools/Scale Tool': { key: 'T', modifiers: [] }, + 'Menu/Edit/Tools/Shear Tool': { key: 'G', modifiers: [] }, + 'Menu/Edit/Duplicate': { key: 'D', modifiers: ['Ctrl', ] }, + 'Controls/Map view/Flip objects horizontally': { key: 'F', modifiers: ['Ctrl', ] }, + 'Controls/Map view/Flip objects vertically': { key: 'F', modifiers: ['Ctrl', 'Alt', ] }, + 'Menu/Edit/Texture Lock': { key: '', modifiers: [] }, + 'Menu/Edit/UV Lock': { key: 'U', modifiers: [] }, + 'Controls/Map view/Move textures down (fine)': { key: 'Down', modifiers: ['Ctrl', ] }, + 'Controls/Map view/Duplicate and move objects forward; Duplicate and move objects down': { key: 'PgDown', modifiers: ['Ctrl', ] }, + 'Controls/Map view/Move objects down; Move objects backward': { key: 'Down', modifiers: [] }, + 'Controls/Map view/Create brush': { key: 'Return', modifiers: [] }, + 'Controls/Map view/Move objects right': { key: 'Right', modifiers: [] }, + 'Controls/Map view/Perform clip': { key: 'Return', modifiers: [] }, + 'Controls/Map view/Make structural': { key: 'S', modifiers: ['Alt', ] }, + 'Controls/Map view/Move textures down (coarse)': { key: 'Down', modifiers: ['Shift', ] }, + 'Controls/Map view/Move textures down': { key: 'Down', modifiers: [] }, + 'Controls/Map view/Toggle clip side': { key: 'Return', modifiers: ['Ctrl', ] }, + 'Controls/Map view/Move textures up (fine)': { key: 'Up', modifiers: ['Ctrl', ] }, + 'Controls/Map view/Duplicate and move objects backward; Duplicate and move objects up': { key: 'PgUp', modifiers: ['Ctrl', ] }, + 'Controls/Map view/Move objects backward; Move objects up': { key: 'PgUp', modifiers: [] }, + 'Controls/Map view/Move objects up; Move objects forward': { key: 'Up', modifiers: [] }, + 'Controls/Map view/Move objects left': { key: 'Left', modifiers: [] }, + 'Controls/Map view/Move objects forward; Move objects down': { key: 'PgDown', modifiers: [] }, + 'Controls/Map view/Duplicate and move objects up; Duplicate and move objects forward': { key: 'Up', modifiers: ['Ctrl', ] }, + 'Controls/Map view/Reveal in texture browser': { key: '', modifiers: [] }, + 'Controls/Map view/Duplicate and move objects down; Duplicate and move objects backward': { key: 'Down', modifiers: ['Ctrl', ] }, + 'Controls/Map view/Duplicate and move objects left': { key: 'Left', modifiers: ['Ctrl', ] }, + 'Controls/Map view/Duplicate and move objects right': { key: 'Right', modifiers: ['Ctrl', ] }, + 'Controls/Map view/View Filter > Hide entity links': { key: '', modifiers: [] }, + 'Controls/Map view/Roll objects clockwise': { key: 'Up', modifiers: ['Alt', ] }, + 'Controls/Map view/View Filter > Toggle show brushes': { key: '', modifiers: [] }, + 'Controls/Map view/Roll objects counter-clockwise': { key: 'Down', modifiers: ['Alt', ] }, + 'Controls/Map view/Yaw objects clockwise': { key: 'Left', modifiers: ['Alt', ] }, + 'Controls/Map view/Move textures up (coarse)': { key: 'Up', modifiers: ['Shift', ] }, + 'Controls/Map view/Yaw objects counter-clockwise': { key: 'Right', modifiers: ['Alt', ] }, + 'Controls/Map view/Pitch objects clockwise': { key: 'PgUp', modifiers: ['Alt', ] }, + 'Controls/Map view/Flip textures vertically': { key: 'F', modifiers: ['Ctrl', 'Alt', ] }, + 'Controls/Map view/Rotate textures counter-clockwise (fine)': { key: 'PgDown', modifiers: ['Ctrl', ] }, + 'Controls/Map view/Pitch objects counter-clockwise': { key: 'PgDown', modifiers: ['Alt', ] }, + 'Controls/Map view/Rotate textures clockwise (fine)': { key: 'PgUp', modifiers: ['Ctrl', ] }, + 'Controls/Map view/Move textures up': { key: 'Up', modifiers: [] }, + 'Controls/Map view/Move textures left': { key: 'Left', modifiers: [] }, + 'Controls/Map view/Move textures left (coarse)': { key: 'Left', modifiers: ['Shift', ] }, + 'Controls/Map view/Move textures left (fine)': { key: 'Left', modifiers: ['Ctrl', ] }, + 'Controls/Map view/Move textures right (coarse)': { key: 'Right', modifiers: ['Shift', ] }, + 'Controls/Map view/Move textures right': { key: 'Right', modifiers: [] }, + 'Controls/Map view/View Filter > Show edges': { key: '', modifiers: [] }, + 'Controls/Map view/Move textures right (fine)': { key: 'Right', modifiers: ['Ctrl', ] }, + 'Controls/Map view/Rotate textures clockwise (coarse)': { key: 'PgUp', modifiers: ['Shift', ] }, + 'Controls/Map view/Rotate textures clockwise': { key: 'PgUp', modifiers: [] }, + 'Controls/Map view/View Filter > Toggle show point entity bounds': { key: '', modifiers: [] }, + 'Controls/Map view/Rotate textures counter-clockwise': { key: 'PgDown', modifiers: [] }, + 'Controls/Map view/Rotate textures counter-clockwise (coarse)': { key: 'PgDown', modifiers: ['Shift', ] }, + 'Controls/Map view/View Filter > Toggle show group bounds': { key: '', modifiers: [] }, + 'Controls/Map view/Flip textures horizontally': { key: 'F', modifiers: ['Ctrl', ] }, + 'Controls/Map view/Reset texture alignment': { key: 'R', modifiers: ['Shift', ] }, + 'Controls/Map view/Reset texture alignment to world aligned': { key: 'R', modifiers: ['Alt', 'Shift', ] }, + 'Controls/Map view/View Filter > Toggle show point entities': { key: '', modifiers: [] }, + 'Controls/Map view/Reset camera zoom': { key: 'Z', modifiers: ['Ctrl', 'Alt', ] }, + 'Controls/Map view/View Filter > Toggle show entity classnames': { key: '', modifiers: [] }, + 'Controls/Map view/Cancel': { key: 'Esc', modifiers: [] }, + 'Controls/Map view/View Filter > Toggle show brush entity bounds': { key: '', modifiers: [] }, + 'Controls/Map view/Cycle map view': { key: 'Space', modifiers: [] }, + 'Controls/Map view/View Filter > Toggle show point entity models': { key: '', modifiers: [] }, + 'Controls/Map view/View Filter > Show textures': { key: '', modifiers: [] }, + 'Controls/Map view/View Filter > Hide textures': { key: '', modifiers: [] }, + 'Controls/Map view/View Filter > Hide faces': { key: '', modifiers: [] }, + 'Controls/Map view/View Filter > Shade faces': { key: '', modifiers: [] }, + 'Controls/Map view/View Filter > Use fog': { key: '', modifiers: [] }, + 'Controls/Map view/View Filter > Show directly selected entity links': { key: '', modifiers: [] }, + 'Controls/Map view/View Filter > Show all entity links': { key: '', modifiers: [] }, + 'Controls/Map view/View Filter > Show transitively selected entity links': { key: '', modifiers: [] }, + 'Controls/Camera/Move forward': { key: 'W', modifiers: [] }, + 'Controls/Camera/Move backward': { key: 'S', modifiers: [] }, + 'Controls/Camera/Move left': { key: 'A', modifiers: [] }, + 'Controls/Camera/Move right': { key: 'D', modifiers: [] }, + 'Controls/Camera/Move up': { key: 'Q', modifiers: [] }, + 'Controls/Camera/Move down': { key: 'X', modifiers: [] }, +}; diff --git a/tools/trenchbroom/manual/shortcuts_helper.js b/tools/trenchbroom/manual/shortcuts_helper.js new file mode 100644 index 0000000..de6f55c --- /dev/null +++ b/tools/trenchbroom/manual/shortcuts_helper.js @@ -0,0 +1,83 @@ +// handles the string in a #key() macro +const key_str = (key) => { + if (keys[key]) { + return "" + keys[key] + ""; + } else { + console.error("unknown key ", key); + return undefined; + } +} + +// Pandoc smart typography converts three periods to …, but this breaks +// our menu item lookups. +const fix_ellipsis = (path) => path.replace("…", "..."); + +const shortcut_str = (shortcut) => { + let result = ""; + + if (shortcut) { + if (shortcut.key == "") { + result = undefined; + } else { + for (i = 0; i < shortcut.modifiers.length; ++i) { + result += key_str(shortcut.modifiers[i]); + } + result += key_str(shortcut.key); + } + } else { + console.error("unknown shortcut ", shortcut); + result += "«unknown shortcut»"; + } + + return result; +} + +const menu_path_str = (path) => path.join(" » "); + +// handles the string in a #menu() macro +const menu_item_str = (key) => { + key = fix_ellipsis(key); + let result = ""; + const item = menu[key]; + + if (item) { + result += menu_path_str(item.path); + const shortcut = shortcut_str(item.shortcut); + if (shortcut) { + result += " (" + shortcut + ")"; + } + } else { + console.error("unknown menu item ", key); + result += "unknown menu item \"" + key + "\""; + } + + result += ""; + return result; +} + +// handles the string in an #action() macro +const action_str = (key) => { + key = fix_ellipsis(key); + + let result = ""; + const item = actions[key]; + + if (item) { + result += shortcut_str(item); + } else { + console.error("unknown action ", key); + result += "unknown action \"" + key + "\""; + } + + result += ""; + return result; +} + +// #key() macros expand into calls to this +const print_key = (key) => document.write(key_str(key)); + +// #menu() macros expand into calls to this +const print_menu_item = (key) => document.write(menu_item_str(key)); + +// #action() macros expand into calls to this +const print_action = (key) => document.write(action_str(key)); diff --git a/tools/trenchbroom/manual/toc_toggler.js b/tools/trenchbroom/manual/toc_toggler.js new file mode 100644 index 0000000..09636be --- /dev/null +++ b/tools/trenchbroom/manual/toc_toggler.js @@ -0,0 +1,16 @@ +(() => { + window.addEventListener("DOMContentLoaded", () => { + const tocToggledClass = "toc_toggled"; + + document.body.querySelector("div#toc_toggler .toc_toggler_button").addEventListener("click", (event) => { + event.preventDefault(); + document.body.classList.toggle(tocToggledClass); + }); + + document.body.querySelectorAll("a").forEach((element) => { + element.addEventListener("click", (event) => { + document.body.classList.remove(tocToggledClass); + }); + }); + }); +})() diff --git a/tools/trenchbroom/miniz.dll b/tools/trenchbroom/miniz.dll new file mode 100644 index 0000000..845b0fc Binary files /dev/null and b/tools/trenchbroom/miniz.dll differ diff --git a/tools/trenchbroom/minizip.dll b/tools/trenchbroom/minizip.dll new file mode 100644 index 0000000..23798f8 Binary files /dev/null and b/tools/trenchbroom/minizip.dll differ diff --git a/tools/trenchbroom/openjp2.dll b/tools/trenchbroom/openjp2.dll new file mode 100644 index 0000000..d8b0fbe Binary files /dev/null and b/tools/trenchbroom/openjp2.dll differ diff --git a/tools/trenchbroom/platforms/qwindows.dll b/tools/trenchbroom/platforms/qwindows.dll new file mode 100644 index 0000000..e9c319d Binary files /dev/null and b/tools/trenchbroom/platforms/qwindows.dll differ diff --git a/tools/trenchbroom/poly2tri.dll b/tools/trenchbroom/poly2tri.dll new file mode 100644 index 0000000..a80d1b3 Binary files /dev/null and b/tools/trenchbroom/poly2tri.dll differ diff --git a/tools/trenchbroom/pugixml.dll b/tools/trenchbroom/pugixml.dll new file mode 100644 index 0000000..ed13563 Binary files /dev/null and b/tools/trenchbroom/pugixml.dll differ diff --git a/tools/trenchbroom/raw.dll b/tools/trenchbroom/raw.dll new file mode 100644 index 0000000..31d2203 Binary files /dev/null and b/tools/trenchbroom/raw.dll differ diff --git a/tools/trenchbroom/shader/ClipHandle.vertsh b/tools/trenchbroom/shader/ClipHandle.vertsh new file mode 100644 index 0000000..ab52470 --- /dev/null +++ b/tools/trenchbroom/shader/ClipHandle.vertsh @@ -0,0 +1,33 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform vec4 Color; +uniform vec3 CameraPosition; +uniform vec4 Position; +uniform float ScalingFactor; +uniform float MaximumDistance; + +varying vec4 vertexColor; + +void main(void) { + vertexColor = Color; + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; +} diff --git a/tools/trenchbroom/shader/ColoredHandle.vertsh b/tools/trenchbroom/shader/ColoredHandle.vertsh new file mode 100644 index 0000000..9e2daa3 --- /dev/null +++ b/tools/trenchbroom/shader/ColoredHandle.vertsh @@ -0,0 +1,27 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +varying vec4 vertexColor; + +void main(void) { + vertexColor = gl_Color; + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; +} diff --git a/tools/trenchbroom/shader/ColoredText.vertsh b/tools/trenchbroom/shader/ColoredText.vertsh new file mode 100644 index 0000000..a0ccdd6 --- /dev/null +++ b/tools/trenchbroom/shader/ColoredText.vertsh @@ -0,0 +1,28 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +varying vec4 vertexColor; + +void main(void) { + vertexColor = gl_Color; + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; + gl_TexCoord[0] = gl_MultiTexCoord0; +} diff --git a/tools/trenchbroom/shader/Compass.fragsh b/tools/trenchbroom/shader/Compass.fragsh new file mode 100644 index 0000000..e2d1592 --- /dev/null +++ b/tools/trenchbroom/shader/Compass.fragsh @@ -0,0 +1,24 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +void main() { + gl_FragColor = gl_Color; +} diff --git a/tools/trenchbroom/shader/Compass.vertsh b/tools/trenchbroom/shader/Compass.vertsh new file mode 100644 index 0000000..d0feebe --- /dev/null +++ b/tools/trenchbroom/shader/Compass.vertsh @@ -0,0 +1,47 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform vec3 CameraPosition; +uniform vec3 LightDirection; +uniform vec4 LightDiffuse; +uniform vec4 LightSpecular; +uniform vec4 MaterialDiffuse; +uniform vec4 MaterialAmbient; +uniform vec4 MaterialSpecular; +uniform float MaterialShininess; +uniform vec4 GlobalAmbient; + +void main(void) { + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; + + vec3 normal = normalize(gl_NormalMatrix * gl_Normal); + float NdotL = max(dot(normal, LightDirection), 0.0); // cosine of normal and light direction + + vec4 diffuse = NdotL * LightDiffuse * MaterialDiffuse; + vec4 ambient = GlobalAmbient * MaterialAmbient; + + vec3 eyeVector = normalize(CameraPosition - gl_Vertex.xyz); + vec3 halfVector = normalize(eyeVector - LightDirection); + float NdotHV = max(-dot(normal, halfVector), 0.0); + vec4 specular = MaterialSpecular * LightSpecular * pow(NdotHV, MaterialShininess); + + gl_FrontColor = vec4((diffuse + ambient + specular).xyz, 1.0); +} diff --git a/tools/trenchbroom/shader/CompassOutline.vertsh b/tools/trenchbroom/shader/CompassOutline.vertsh new file mode 100644 index 0000000..38b18ba --- /dev/null +++ b/tools/trenchbroom/shader/CompassOutline.vertsh @@ -0,0 +1,27 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform vec4 Color; + +void main(void) { + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; + gl_FrontColor = Color; +} diff --git a/tools/trenchbroom/shader/Edge.fragsh b/tools/trenchbroom/shader/Edge.fragsh new file mode 100644 index 0000000..eb75a4b --- /dev/null +++ b/tools/trenchbroom/shader/Edge.fragsh @@ -0,0 +1,39 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform bool ApplyTinting; +uniform vec4 TintColor; + +varying vec4 worldCoordinates; +varying vec4 vertexColor; + +vec3 applySoftMapBoundsTint(vec3 inputFragColor, vec3 worldCoords); + +void main() { + gl_FragColor = vertexColor; + + if (ApplyTinting) { + gl_FragColor = vec4(gl_FragColor.rgb * TintColor.rgb * TintColor.a, gl_FragColor.a); + gl_FragColor = clamp(2.0 * gl_FragColor, 0.0, 1.0); + } + + gl_FragColor.rgb = applySoftMapBoundsTint(gl_FragColor.rgb, worldCoordinates.xyz); +} diff --git a/tools/trenchbroom/shader/Edge.vertsh b/tools/trenchbroom/shader/Edge.vertsh new file mode 100644 index 0000000..b11ae53 --- /dev/null +++ b/tools/trenchbroom/shader/Edge.vertsh @@ -0,0 +1,37 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform vec4 Color; +uniform bool UseUniformColor; + +varying vec4 worldCoordinates; +varying vec4 vertexColor; + +void main(void) { + if (UseUniformColor) { + vertexColor = Color; + } else { + vertexColor = gl_Color; + } + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; + // Brushes are assumed to be in world space already (Face.vertsh also assumes this) + worldCoordinates = gl_Vertex; +} diff --git a/tools/trenchbroom/shader/EntityModel.fragsh b/tools/trenchbroom/shader/EntityModel.fragsh new file mode 100644 index 0000000..c2d835f --- /dev/null +++ b/tools/trenchbroom/shader/EntityModel.fragsh @@ -0,0 +1,55 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform float Brightness; +uniform sampler2D Material; +uniform bool ApplyTinting; +uniform vec4 TintColor; +uniform bool GrayScale; + +varying vec4 worldCoordinates; + +vec3 applySoftMapBoundsTint(vec3 inputFragColor, vec3 worldCoords); + +void main() { + vec4 texel = texture2D(Material, gl_TexCoord[0].st); + + // Assume alpha masked or opaque. + // TODO: Make this optional if we gain support for translucent textures + if (texel.a < 0.5) { + discard; + } + + gl_FragColor = vec4(vec3(Brightness / 2.0 * texel), texel.a); + gl_FragColor = clamp(2 * gl_FragColor, 0.0, 1.0); + + if (GrayScale) { + float gray = dot(gl_FragColor.rgb, vec3(0.299, 0.587, 0.114)); + gl_FragColor = vec4(gray, gray, gray, gl_FragColor.a); + } + + if (ApplyTinting) { + gl_FragColor = vec4(gl_FragColor.rgb * TintColor.rgb * TintColor.a, gl_FragColor.a); + gl_FragColor = clamp(2.0 * gl_FragColor, 0.0, 1.0); + } + + gl_FragColor.rgb = applySoftMapBoundsTint(gl_FragColor.rgb, worldCoordinates.xyz); +} diff --git a/tools/trenchbroom/shader/EntityModel.vertsh b/tools/trenchbroom/shader/EntityModel.vertsh new file mode 100644 index 0000000..82ab42d --- /dev/null +++ b/tools/trenchbroom/shader/EntityModel.vertsh @@ -0,0 +1,159 @@ +#version 120 + +/* + Copyright (C) 2020 MaxED + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform mat4 ModelMatrix; +uniform mat4 ViewMatrix; +uniform vec3 CameraPosition; +uniform vec3 CameraDirection; +uniform vec3 CameraRight; +uniform vec3 CameraUp; + +// see Orientation enum in EntityModel.h +uniform int Orientation; + +varying vec4 worldCoordinates; + +mat4 getScaleMatrix() { + float sx = length(vec3(ModelMatrix[0])); + float sy = length(vec3(ModelMatrix[1])); + float sz = length(vec3(ModelMatrix[2])); + + return mat4( + vec4(sx, 0.0, 0.0, 0.0), + vec4(0.0, sy, 0.0, 0.0), + vec4(0.0, 0.0, sz, 0.0), + vec4(0.0, 0.0, 0.0, 1.0) + ); +} + +mat4 getViewPlaneParallelUprightModelMatrix() { + // Faces view plane, up is towards the heavens. + vec3 right = CameraRight; + vec3 up = vec3(0.0, 0.0, 1.0); + vec3 normal = normalize(cross(right, up)); + + return mat4( + vec4(right, 0.0), + vec4(up, 0.0), + vec4(normal, 0.0), + ModelMatrix[3] + ) * getScaleMatrix(); +} + +mat4 getFacingUprightModelMatrix() { + // Faces camera origin, up is towards the heavens. + vec3 toCam = CameraPosition - vec3(ModelMatrix[3]); + vec3 up = vec3(0.0, 0.0, 1.0); + vec3 right = normalize(cross(up, toCam)); + vec3 normal = normalize(cross(right, up)); + + return mat4( + vec4(right, 0.0), + vec4(up, 0.0), + vec4(normal, 0.0), + ModelMatrix[3] + ) * getScaleMatrix(); +} + +mat4 getViewPlaneParallelModelMatrix() { + // Faces view plane, up is towards the top of the screen. + vec3 normal = -CameraDirection; + vec3 right = CameraRight; + vec3 up = CameraUp; + + return mat4( + vec4(right, 0.0), + vec4(up, 0.0), + vec4(normal, 0.0), + ModelMatrix[3] + ) * getScaleMatrix(); +} + +float extractRollAngle(mat4 rotation) { + if (abs(rotation[0][2]) != 1.0) { + float theta = -asin(rotation[0][1]); + float cosTheta = cos(theta); + return atan(rotation[1][2] / cosTheta, rotation[2][2] / cosTheta); + } else if (rotation[0][2] == -1.0) { + return atan(rotation[1][0], rotation[2][0]); + } else { + return atan(-rotation[1][0], -rotation[2][0]); + } +} + +mat4 getViewPlaneParallelOrientedModelMatrix() { + // Faces view plane, but obeys roll value. + + mat4 transform = mat4( + ModelMatrix[0], + ModelMatrix[1], + ModelMatrix[2], + vec4(0.0, 0.0, 0.0, 1.0) + ); + + // the rotated unit vectors + vec3 x = normalize((transform * vec4(1.0, 0.0, 0.0, 1.0)).xyz); + vec3 y = normalize(cross((transform * vec4(0.0, 0.0, 1.0, 1.0)).xyz, x)); + vec3 z = normalize(cross(x, y)); + + mat4 rotation = mat4( + vec4(x, 0.0), + vec4(y, 0.0), + vec4(z, 0.0), + vec4(0.0, 0.0, 0.0, 1.0) + ); + + float roll = extractRollAngle(rotation); + float s = sin(roll); + float c = cos(roll); + + vec3 normal = -CameraDirection; + vec3 right = CameraRight * c + CameraUp * s; + vec3 up = CameraRight * -s + CameraUp * c; + + return mat4( + vec4(right, 0.0), + vec4(up, 0.0), + vec4(normal, 0.0), + ModelMatrix[3] + ) * getScaleMatrix(); +} + +mat4 getModelMatrix() { + if (Orientation == 0) { + return getViewPlaneParallelUprightModelMatrix(); + } else if (Orientation == 1) { + return getFacingUprightModelMatrix(); + } else if (Orientation == 2) { + return getViewPlaneParallelModelMatrix(); + } else if (Orientation == 4) { + return getViewPlaneParallelOrientedModelMatrix(); + } + + // Pitch yaw roll are independent of camera. + return ModelMatrix; +} + +void main(void) { + gl_Position = gl_ProjectionMatrix * ViewMatrix * getModelMatrix() * gl_Vertex; + worldCoordinates = ModelMatrix * gl_Vertex; + gl_TexCoord[0] = gl_MultiTexCoord0; +} diff --git a/tools/trenchbroom/shader/Face.fragsh b/tools/trenchbroom/shader/Face.fragsh new file mode 100644 index 0000000..c8f6a95 --- /dev/null +++ b/tools/trenchbroom/shader/Face.fragsh @@ -0,0 +1,111 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform float Brightness; +uniform float Alpha; +uniform bool EnableMasked; +uniform bool ApplyMaterial; +uniform sampler2D Material; +uniform bool ApplyTinting; +uniform vec4 TintColor; +uniform bool GrayScale; +uniform bool RenderGrid; +uniform float GridSize; +uniform float GridAlpha; +uniform vec3 GridColor; +uniform bool ShadeFaces; +uniform bool ShowFog; + +varying vec4 modelCoordinates; +varying vec3 modelNormal; +varying vec4 faceColor; +varying vec3 viewVector; + +float grid(vec3 coords, vec3 normal, float gridSize, float minGridSize, float lineWidthFactor); +vec3 applySoftMapBoundsTint(vec3 inputFragColor, vec3 worldCoords); + +void main() { + if (ApplyMaterial) + gl_FragColor = texture2D(Material, gl_TexCoord[0].st); + else + gl_FragColor = faceColor; + + // Assume alpha masked or opaque. + // TODO: Make this optional if we gain support for translucent textures + if (EnableMasked && gl_FragColor.a < 0.5) { + discard; + } + + gl_FragColor = vec4(vec3(Brightness / 2.0 * gl_FragColor), gl_FragColor.a); + gl_FragColor = clamp(2.0 * gl_FragColor, 0.0, 1.0); + gl_FragColor.a = Alpha; + + if (GrayScale) { + float gray = dot(gl_FragColor.rgb, vec3(0.299, 0.587, 0.114)); + gl_FragColor = vec4(gray, gray, gray, gl_FragColor.a); + } + + if (ApplyTinting) { + gl_FragColor = vec4(gl_FragColor.rgb * TintColor.rgb * TintColor.a, gl_FragColor.a); + float brightnessCorrection = 1.0 / max(max(abs(TintColor.r), abs(TintColor.g)), abs(TintColor.b)); + gl_FragColor = clamp(brightnessCorrection * gl_FragColor, 0.0, 1.0); + } + + if (ShadeFaces) { + // angular dimming ( can be controlled with dimStrength ) + // TODO: make view option + float dimStrength = 0.25; + float angleDim = dot(normalize(viewVector), normalize(modelNormal)) * dimStrength + (1.0 - dimStrength); + + gl_FragColor.rgb *= angleDim; + } + + if (ShowFog) { + float distance = length(viewVector); + + // TODO: make view options + vec3 fogColor = vec3(0.5, 0.5, 0.5); + float maxFogAmount = 0.15; + float fogBias = 0.0; + float fogScale = 0.00075; + float fogMinDistance = 512.0; + + float fogFactor = max(distance - fogMinDistance, 0.0) * fogScale; + + //gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, clamp(( gl_FragCoord.z / gl_FragCoord.w ) * fogScale + fogBias, 0.0, maxFogAmount )); + gl_FragColor.rgb = mix(gl_FragColor.rgb, fogColor, clamp(fogFactor + fogBias, 0.0, maxFogAmount)); + } + + if (RenderGrid && GridAlpha > 0.0) { + vec3 coords = modelCoordinates.xyz; + + // get the maximum distance in world space between this and the neighbouring fragments + float maxWorldSpaceChange = max(length(dFdx(coords)), length(dFdy(coords))); + + // apply the Nyquist theorem to get the smallest grid size that would make sense to render for this fragment + float minGridSize = 2.0 * maxWorldSpaceChange; + + float gridValue = grid(coords, modelNormal.xyz, GridSize, minGridSize, 1.0); + gl_FragColor.rgb = mix(gl_FragColor.rgb, GridColor, gridValue * GridAlpha); + } + + gl_FragColor.rgb = applySoftMapBoundsTint(gl_FragColor.rgb, modelCoordinates.xyz); +} diff --git a/tools/trenchbroom/shader/Face.vertsh b/tools/trenchbroom/shader/Face.vertsh new file mode 100644 index 0000000..73fbc57 --- /dev/null +++ b/tools/trenchbroom/shader/Face.vertsh @@ -0,0 +1,37 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform vec4 Color; +uniform vec3 CameraPosition; + +varying vec4 modelCoordinates; +varying vec3 modelNormal; +varying vec4 faceColor; +varying vec3 viewVector; + +void main(void) { + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; + gl_TexCoord[0] = gl_MultiTexCoord0; + modelCoordinates = gl_Vertex; + modelNormal = gl_Normal; + faceColor = Color; + viewVector = CameraPosition - gl_Vertex.xyz; +} \ No newline at end of file diff --git a/tools/trenchbroom/shader/Grid.fragsh b/tools/trenchbroom/shader/Grid.fragsh new file mode 100644 index 0000000..28fa3c6 --- /dev/null +++ b/tools/trenchbroom/shader/Grid.fragsh @@ -0,0 +1,126 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +float getSoftStripes(float value, float gridSize, float stripeSize) { + float mainVal = value * gridSize; + float filterWidth = fwidth(value); + float edge = filterWidth * gridSize * 2.0; + + // major line shading, currently set to place a major line every 64 units + float mValue = 1.0 / (64.0 * gridSize); + float triMajor = abs(2.0 * fract(mainVal * mValue) - 1.0); + float isMajor = step(1.0 - mValue, triMajor); + + float outIntensity = isMajor * 0.7 + 0.85; // tweak intensities here + float sSize = stripeSize; + + float triangle = abs(2.0 * fract(mainVal) - 1.0); + return smoothstep(sSize - edge, sSize + edge, triangle) * outIntensity; +} + +/** + * Draws two overlaid grids + * + * @param inCoords fragment coordinates (TODO: document units) + * @param gridRatio the reciprocal of the first grid size, e.g. (1/16) for a 16 unit grid + * @param gridRatio2 the reciprocal of the second grid size, e.g. (1/16) for a 16 unit grid + * @param lineWidth the line width (TODO: document units) + * @param gridBlend the fraction of the two grids to draw, between 0 and 1, + * where 0.0 means 100% of grid one, and 1.0 means 100% of grid two. + */ +float gridLinesSoft(vec2 inCoords, float gridRatio, float gridRatio2, float lineWidth, float gridBlend) { + float stripeRatio = lineWidth * gridRatio; + float stripeRatio2 = lineWidth * gridRatio2; + float stripeSize = 1.0 - stripeRatio; + float stripeSize2 = 1.0 - stripeRatio2; + + float theGrid, nextGrid; + + theGrid = getSoftStripes(inCoords.x, gridRatio, stripeSize); + theGrid = max(theGrid, getSoftStripes(inCoords.y, gridRatio, stripeSize)); + nextGrid = getSoftStripes(inCoords.x, gridRatio2, stripeSize2); + nextGrid = max(nextGrid, getSoftStripes(inCoords.y, gridRatio2, stripeSize2)); + + theGrid = mix(theGrid, nextGrid, gridBlend); + + return theGrid * 0.5; +} + +/** + * Given a valid grid size, returns the next larger one. + */ +float gridNextLarger(float size) { + return 2.0 * size; +} + +/** + * Given any size, finds the next smaller size that is a proper grid size. + * Returns the input unmodified if it's already a grid size. + */ +float gridFloor(float size) { + return exp2(floor(log2(size))); +} + +/* + * Computes the grid for the current fragment with the given parameters. + * + * @param coords the coordinates of the fragment in world space (same units as gridSize) + * @param normal the normal vector of the fragment + * @param gridSize the actual size of the grid (e.g. 16, 32, 64, etc.) + * @param minGridSize the minimal grid size to render (to fade out smaller grids to prevent moire etc.) + * @param lineWidthFactor a factor for the line width of the grid + * + * @return opacity of the grid line to draw on this fragment, in [0..1] + */ +float grid(vec3 coords, vec3 normal, float gridSize, float minGridSize, float lineWidthFactor) { + float lineWidth = (gridSize < 1.0 ? (1.0 / 32.0) + : (gridSize < 4.0 ? 0.25 : 0.5)) * lineWidthFactor; + + // magic number to make the grid fade sooner, preventing aliasing + float minGridSizeToRender = minGridSize * 2.0; + + float baseGridSize = gridFloor(minGridSizeToRender); + if (gridSize > baseGridSize) { + baseGridSize = gridSize; + } + float nextGridSize = gridNextLarger(baseGridSize); + + // This is 0 if we want to render just baseGridSize, and 1 if we want to fully render at nextGridSize + float gridBlend = smoothstep(baseGridSize, nextGridSize, minGridSizeToRender); + + float gridRatio = 1.0 / baseGridSize; + float gridRatio2 = 1.0 / nextGridSize; + + vec2 baseCoords; // coordinates used for overlay creation + + if (abs(normal.x) > abs(normal.y)) { + if (abs(normal.x) > abs(normal.z)) + baseCoords = coords.yz; + else + baseCoords = coords.xy; + } else if (abs(normal.y) > abs(normal.z)) { + baseCoords = coords.xz; + } else { + baseCoords = coords.xy; + } + + return gridLinesSoft(baseCoords, gridRatio, gridRatio2, lineWidth, gridBlend); +} diff --git a/tools/trenchbroom/shader/Grid2D.fragsh b/tools/trenchbroom/shader/Grid2D.fragsh new file mode 100644 index 0000000..6209e99 --- /dev/null +++ b/tools/trenchbroom/shader/Grid2D.fragsh @@ -0,0 +1,41 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform bool RenderGrid; +uniform vec4 GridColor; +uniform float GridSize; +uniform float GridAlpha; +uniform float CameraZoom; + +uniform vec3 Normal; + +varying vec4 modelCoordinates; + +float grid(vec3 coords, vec3 normal, float gridSize, float minGridSize, float lineWidthFactor); + +void main() { + if (RenderGrid && GridAlpha > 0.0) { + float minGridSize = 5.0 / CameraZoom; + float lineWidthFactor = 2.0 / CameraZoom; + float gridValue = grid(modelCoordinates.xyz, Normal.xyz, GridSize, minGridSize, lineWidthFactor); + gl_FragColor = vec4(GridColor.xyz, gridValue * GridAlpha); + } +} diff --git a/tools/trenchbroom/shader/Grid2D.vertsh b/tools/trenchbroom/shader/Grid2D.vertsh new file mode 100644 index 0000000..e0073d8 --- /dev/null +++ b/tools/trenchbroom/shader/Grid2D.vertsh @@ -0,0 +1,27 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +varying vec4 modelCoordinates; + +void main(void) { + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; + modelCoordinates = gl_Vertex; +} \ No newline at end of file diff --git a/tools/trenchbroom/shader/Handle.fragsh b/tools/trenchbroom/shader/Handle.fragsh new file mode 100644 index 0000000..cf28dfa --- /dev/null +++ b/tools/trenchbroom/shader/Handle.fragsh @@ -0,0 +1,26 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +varying vec4 vertexColor; + +void main() { + gl_FragColor = vertexColor; +} diff --git a/tools/trenchbroom/shader/Handle.vertsh b/tools/trenchbroom/shader/Handle.vertsh new file mode 100644 index 0000000..3e4678f --- /dev/null +++ b/tools/trenchbroom/shader/Handle.vertsh @@ -0,0 +1,29 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform vec4 Color; + +varying vec4 vertexColor; + +void main(void) { + vertexColor = Color; + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; +} diff --git a/tools/trenchbroom/shader/LinkArrow.fragsh b/tools/trenchbroom/shader/LinkArrow.fragsh new file mode 100644 index 0000000..10d9e8d --- /dev/null +++ b/tools/trenchbroom/shader/LinkArrow.fragsh @@ -0,0 +1,35 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform float MaxDistance; +uniform float Alpha; +uniform bool IsOrtho; + +varying float distanceFromCamera; +varying vec4 color; + +void main() { + float scale = 1.0; + if (!IsOrtho) { + scale = (1.0 - clamp(distanceFromCamera / MaxDistance * 0.2 + 0.25, 0.0, 1.0));// * 0.35 + 0.65); + } + gl_FragColor = vec4(color.rgb, color.a * scale * Alpha); +} \ No newline at end of file diff --git a/tools/trenchbroom/shader/LinkArrow.vertsh b/tools/trenchbroom/shader/LinkArrow.vertsh new file mode 100644 index 0000000..4b8b644 --- /dev/null +++ b/tools/trenchbroom/shader/LinkArrow.vertsh @@ -0,0 +1,157 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform vec3 CameraPosition; +uniform bool IsOrtho; +uniform float Zoom; + +attribute vec3 arrowPosition; +attribute vec3 lineDir; + +varying float distanceFromCamera; +varying vec4 color; + +const float almostZero = 0.001; + +struct Quat { + float r; + vec3 v; +}; + +Quat setRotation(vec3 axis, float angle) { + Quat quat; + quat.r = cos(angle / 2.0f); + quat.v = axis * sin(angle / 2.0f); + return quat; +} + +bool eqEpsilon(float a, float b, float epsilon) { + return abs(a - b) < epsilon; +} + +/** + * Creates a new quaternion that rotates the 1st given vector onto the 2nd given vector. Both vectors are + * expected to be normalized. + */ +Quat makeQuat(vec3 from, vec3 to) { + float cosAngle = dot(from, to); + + // check for `from` and `to` equal + if (eqEpsilon(cosAngle, 1.0, almostZero)) { + return setRotation(vec3(0.0, 0.0, 1.0), 0.0); + } + + // check for `from` and `to` opposite + if (eqEpsilon(cosAngle, -1.0, almostZero)) { + // need to find a rotation axis that is perpendicular to `from` + vec3 axis = cross(from, vec3(0.0, 0.0, 1.0)); + if (dot(axis, axis) < 0.01) { + axis = cross(from, vec3(1.0, 0.0, 0.0)); + } + return setRotation(normalize(axis), radians(180.0)); + } + + vec3 axis = normalize(cross(from, to)); + float angle = acos(cosAngle); + return setRotation(axis, angle); +} + +Quat quatMult(Quat left, Quat right) { + float t = right.r; + vec3 w = right.v; + + float nx = left.r * w.x + t * left.v.x + left.v.y * w.z - left.v.z * w.y; + float ny = left.r * w.y + t * left.v.y + left.v.z * w.x - left.v.x * w.z; + float nz = left.r * w.z + t * left.v.z + left.v.x * w.y - left.v.y * w.x; + + Quat result; + result.r = left.r * t - dot(left.v, w); + result.v[0] = nx; + result.v[1] = ny; + result.v[2] = nz; + return result; +} + +Quat conjugated(Quat left) { + Quat result; + result.r = left.r; + result.v = -left.v; + return result; +} + +vec3 quatMult(Quat left, vec3 right) { + Quat p; + p.r = 0.0; + p.v = right; + p = quatMult(quatMult(left, p), conjugated(left)); + return p.v; +} + +/** + Computes the CCW angle between axis and vector in relation to the given up vector. + All vectors are expected to be normalized. + */ +float measureAngle(vec3 vec, vec3 axis, vec3 up) { + float cosAngle = dot(vec, axis); + if (eqEpsilon(+cosAngle, 1.0, almostZero)) { + return 0.0; + } + if (eqEpsilon(-cosAngle, 1.0, almostZero)) { + return radians(180.0); + } + vec3 crossProd = cross(axis, vec); + if (dot(crossProd, up) > -almostZero) { + return acos(cosAngle); + } + return radians(360.0) - acos(cosAngle); +} + +void main(void) { + Quat rotateFromPosXToLineDir = makeQuat(vec3(1.0, 0.0, 0.0), lineDir); + + // the above will point the arrow along the line, but we also want to roll it so it faces the camera. + // see: http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-17-quaternions/#how-do-i-find-the-rotation-between-2-vectors- + vec3 desiredUp = normalize(CameraPosition - arrowPosition); + vec3 desiredRight = cross(lineDir, desiredUp); + desiredUp = normalize(cross(desiredRight, lineDir)); // make desiredUp perpendicular to the lineDir + + vec3 currentUp = quatMult(rotateFromPosXToLineDir, vec3(0.0, 0.0, 1.0)); + + // We want to specifically rotate about `lineDir` only, so can't use makeQuat() (which picks the rotation axis itself + // and could accidentally flip the arrow the wrong way instead of rolling it 180 degrees.) + Quat fixUp = setRotation(lineDir, -measureAngle(currentUp, desiredUp, lineDir)); + + distanceFromCamera = length(CameraPosition - arrowPosition); + + // scale up as you get further away, to a maximum of 4x at 2048 units away + float scaleFactor = 1.0; + if (IsOrtho) { + scaleFactor = clamp(1.0 / Zoom, 1.0, 4.0); + } else { + scaleFactor = mix(1.0, 4.0, smoothstep(0.0, 2048.0, distanceFromCamera)); + } + + // now apply the scale, rotations, and translation to gl_Vertex + vec3 worldVert = arrowPosition + quatMult(quatMult(fixUp, rotateFromPosXToLineDir), gl_Vertex.xyz * scaleFactor); + + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(worldVert, 1.0); + color = gl_Color; +} diff --git a/tools/trenchbroom/shader/LinkLine.fragsh b/tools/trenchbroom/shader/LinkLine.fragsh new file mode 100644 index 0000000..10d9e8d --- /dev/null +++ b/tools/trenchbroom/shader/LinkLine.fragsh @@ -0,0 +1,35 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform float MaxDistance; +uniform float Alpha; +uniform bool IsOrtho; + +varying float distanceFromCamera; +varying vec4 color; + +void main() { + float scale = 1.0; + if (!IsOrtho) { + scale = (1.0 - clamp(distanceFromCamera / MaxDistance * 0.2 + 0.25, 0.0, 1.0));// * 0.35 + 0.65); + } + gl_FragColor = vec4(color.rgb, color.a * scale * Alpha); +} \ No newline at end of file diff --git a/tools/trenchbroom/shader/LinkLine.vertsh b/tools/trenchbroom/shader/LinkLine.vertsh new file mode 100644 index 0000000..d3e68c5 --- /dev/null +++ b/tools/trenchbroom/shader/LinkLine.vertsh @@ -0,0 +1,31 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform vec3 CameraPosition; + +varying float distanceFromCamera; +varying vec4 color; + +void main(void) { + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; + distanceFromCamera = length(CameraPosition - gl_Vertex.xyz); + color = gl_Color; +} diff --git a/tools/trenchbroom/shader/MapBounds.fragsh b/tools/trenchbroom/shader/MapBounds.fragsh new file mode 100644 index 0000000..abf2dcb --- /dev/null +++ b/tools/trenchbroom/shader/MapBounds.fragsh @@ -0,0 +1,34 @@ +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform bool ShowSoftMapBounds; +uniform vec3 SoftMapBoundsMin; +uniform vec3 SoftMapBoundsMax; +uniform vec4 SoftMapBoundsColor; + +vec3 applySoftMapBoundsTint(vec3 inputFragColor, vec3 worldCoords) { + if (ShowSoftMapBounds) { + bool outside = any(greaterThan(worldCoords, SoftMapBoundsMax)) || any(lessThan(worldCoords, SoftMapBoundsMin)); + + if (outside) { + return mix(gl_FragColor.rgb, SoftMapBoundsColor.rgb, SoftMapBoundsColor.a); + } + } + return inputFragColor; +} diff --git a/tools/trenchbroom/shader/MaterialBrowser.fragsh b/tools/trenchbroom/shader/MaterialBrowser.fragsh new file mode 100644 index 0000000..b69b8ac --- /dev/null +++ b/tools/trenchbroom/shader/MaterialBrowser.fragsh @@ -0,0 +1,37 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform float Brightness; +uniform sampler2D Material; +uniform bool ApplyTinting; +uniform vec4 TintColor; + +void main() { + gl_FragColor = texture2D(Material, gl_TexCoord[0].st); + + gl_FragColor = vec4(vec3(Brightness / 2.0 * gl_FragColor), gl_FragColor.a); + gl_FragColor = clamp(2.0 * gl_FragColor, 0.0, 1.0); + + if (ApplyTinting) { + gl_FragColor = vec4(gl_FragColor.rgb * TintColor.rgb * TintColor.a, gl_FragColor.a); + gl_FragColor = clamp(2.0 * gl_FragColor, 0.0, 1.0); + } +} diff --git a/tools/trenchbroom/shader/MaterialBrowser.vertsh b/tools/trenchbroom/shader/MaterialBrowser.vertsh new file mode 100644 index 0000000..21248d1 --- /dev/null +++ b/tools/trenchbroom/shader/MaterialBrowser.vertsh @@ -0,0 +1,25 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +void main(void) { + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; + gl_TexCoord[0] = gl_MultiTexCoord0; +} diff --git a/tools/trenchbroom/shader/MaterialBrowserBorder.fragsh b/tools/trenchbroom/shader/MaterialBrowserBorder.fragsh new file mode 100644 index 0000000..cf28dfa --- /dev/null +++ b/tools/trenchbroom/shader/MaterialBrowserBorder.fragsh @@ -0,0 +1,26 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +varying vec4 vertexColor; + +void main() { + gl_FragColor = vertexColor; +} diff --git a/tools/trenchbroom/shader/MaterialBrowserBorder.vertsh b/tools/trenchbroom/shader/MaterialBrowserBorder.vertsh new file mode 100644 index 0000000..cf7b3e0 --- /dev/null +++ b/tools/trenchbroom/shader/MaterialBrowserBorder.vertsh @@ -0,0 +1,27 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +varying vec4 vertexColor; + +void main(void) { + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; + vertexColor = gl_Color; +} diff --git a/tools/trenchbroom/shader/MiniMapEdge.fragsh b/tools/trenchbroom/shader/MiniMapEdge.fragsh new file mode 100644 index 0000000..1f05bca --- /dev/null +++ b/tools/trenchbroom/shader/MiniMapEdge.fragsh @@ -0,0 +1,34 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform vec4 Color; + +uniform vec3 BoundsMin; +uniform vec3 BoundsMax; + +varying vec4 vertexWorldPosition; + +void main() { + gl_FragColor = Color; + if (any(lessThan(vertexWorldPosition.xyz, BoundsMin)) || + any(greaterThan(vertexWorldPosition.xyz, BoundsMax))) + gl_FragColor.a = 0.05; +} diff --git a/tools/trenchbroom/shader/MiniMapEdge.vertsh b/tools/trenchbroom/shader/MiniMapEdge.vertsh new file mode 100644 index 0000000..037c386 --- /dev/null +++ b/tools/trenchbroom/shader/MiniMapEdge.vertsh @@ -0,0 +1,27 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +varying vec4 vertexWorldPosition; + +void main(void) { + vertexWorldPosition = gl_Vertex; + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; +} diff --git a/tools/trenchbroom/shader/Text.fragsh b/tools/trenchbroom/shader/Text.fragsh new file mode 100644 index 0000000..17dfb05 --- /dev/null +++ b/tools/trenchbroom/shader/Text.fragsh @@ -0,0 +1,28 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +varying vec4 vertexColor; +uniform sampler2D Texture; + +void main() { + vec4 texel = texture2D(Texture, gl_TexCoord[0].st); + gl_FragColor = vec4(vertexColor.r, vertexColor.g, vertexColor.b, vertexColor.a * texel.r); +} diff --git a/tools/trenchbroom/shader/Text.vertsh b/tools/trenchbroom/shader/Text.vertsh new file mode 100644 index 0000000..397c683 --- /dev/null +++ b/tools/trenchbroom/shader/Text.vertsh @@ -0,0 +1,30 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform vec4 Color; + +varying vec4 vertexColor; + +void main(void) { + vertexColor = Color; + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; + gl_TexCoord[0] = gl_MultiTexCoord0; +} diff --git a/tools/trenchbroom/shader/TextBackground.fragsh b/tools/trenchbroom/shader/TextBackground.fragsh new file mode 100644 index 0000000..cf28dfa --- /dev/null +++ b/tools/trenchbroom/shader/TextBackground.fragsh @@ -0,0 +1,26 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +varying vec4 vertexColor; + +void main() { + gl_FragColor = vertexColor; +} diff --git a/tools/trenchbroom/shader/TextBackground.vertsh b/tools/trenchbroom/shader/TextBackground.vertsh new file mode 100644 index 0000000..9e2daa3 --- /dev/null +++ b/tools/trenchbroom/shader/TextBackground.vertsh @@ -0,0 +1,27 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +varying vec4 vertexColor; + +void main(void) { + vertexColor = gl_Color; + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; +} diff --git a/tools/trenchbroom/shader/Triangle.fragsh b/tools/trenchbroom/shader/Triangle.fragsh new file mode 100644 index 0000000..e557bd9 --- /dev/null +++ b/tools/trenchbroom/shader/Triangle.fragsh @@ -0,0 +1,43 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform bool ApplyTinting; +uniform vec4 TintColor; + +varying vec4 vertexColor; +varying vec4 modelCoordinates; +varying vec3 modelNormal; +varying vec3 viewVector; + +void main() { + gl_FragColor = vertexColor; + + if (ApplyTinting) { + gl_FragColor = vec4(gl_FragColor.rgb * TintColor.rgb * TintColor.a, gl_FragColor.a); + gl_FragColor = clamp(2.0 * gl_FragColor, 0.0, 1.0); + } + + // angular dimming ( can be controlled with dimStrength ) + float dimStrength = 0.5; + float angleDim = dot(normalize(viewVector), normalize(modelNormal)) * dimStrength + (1.0 - dimStrength); + + gl_FragColor.rgb *= angleDim; +} diff --git a/tools/trenchbroom/shader/Triangle.vertsh b/tools/trenchbroom/shader/Triangle.vertsh new file mode 100644 index 0000000..3885466 --- /dev/null +++ b/tools/trenchbroom/shader/Triangle.vertsh @@ -0,0 +1,38 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform vec3 CameraPosition; +uniform vec4 Color; +uniform bool UseColor; + +varying vec4 vertexColor; +varying vec3 modelNormal; +varying vec3 viewVector; + +void main(void) { + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; + if (UseColor) + vertexColor = Color; + else + vertexColor = gl_Color; + modelNormal = gl_Normal; + viewVector = CameraPosition - gl_Vertex.xyz; +} diff --git a/tools/trenchbroom/shader/UVView.fragsh b/tools/trenchbroom/shader/UVView.fragsh new file mode 100644 index 0000000..e9b963f --- /dev/null +++ b/tools/trenchbroom/shader/UVView.fragsh @@ -0,0 +1,114 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform float Brightness; +uniform bool ApplyMaterial; +uniform sampler2D Material; +uniform bool RenderGrid; +uniform vec2 GridSizes; +uniform vec4 GridColor; +uniform vec2 GridScales; +uniform mat4 GridMatrix; +uniform vec2 GridDivider; +uniform float CameraZoom; +uniform float DpiScale; + +varying vec4 modelCoordinates; +varying vec3 modelNormal; +varying vec4 faceColor; + +// Returns a measure for the closeness of the given coord from the next grid line, where 1 means the coord is on a +// grid line and 0 means the coord is exactly between two adjacent grid lines. +float closeness(float coord, float gridSize) { + return abs(2.0 * fract(coord / gridSize) - 1.0); +} + +float getSoftStripes(float coord, float gridDivider, float gridSize, float stripeSize) { + // size of the minor and major grids + float minorGridSize = gridSize / gridDivider; + float majorGridSize = gridSize; + + // How close is the coord to the next major and minor grid lines? + float minorCloseness = closeness(coord, minorGridSize); + float majorCloseness = closeness(coord, majorGridSize); + float isMajor = step(1.0 - 1.0 / gridDivider, majorCloseness); + + float outIntensity = isMajor * 0.9 + 0.65; // tweak intensities here + + float edge = 2.0 * fwidth(coord) / minorGridSize; + return smoothstep(stripeSize - edge, stripeSize + edge, minorCloseness) * outIntensity; +} + +void gridLinesSoft(vec2 inCoords) { + // the width of the grid lines, corrected by the texture scaling factors and the camera zoom level + vec2 lineWidths = abs(1.0 / GridScales / CameraZoom) * DpiScale; + // the widths of each grid stripe + vec2 stripeWidths = GridSizes / GridDivider; + // ratio of the line widths and the stripe widths + vec2 stripeRatios = lineWidths / stripeWidths; + vec2 stripeSizes = 1.0 - stripeRatios; + + float alpha = max(getSoftStripes(inCoords.x, GridDivider.x, GridSizes.x, stripeSizes.x), + getSoftStripes(inCoords.y, GridDivider.y, GridSizes.y, stripeSizes.y)); + + gl_FragColor.rgb = mix(gl_FragColor.rgb, GridColor.rgb, alpha * GridColor.a * 0.5); +} + +void main() { + if (ApplyMaterial) + gl_FragColor = texture2D(Material, gl_TexCoord[0].st); + else + gl_FragColor = faceColor; + + gl_FragColor = vec4(vec3(Brightness / 2.0 * gl_FragColor), gl_FragColor.a); + gl_FragColor = clamp(2.0 * gl_FragColor, 0.0, 1.0); + + if (RenderGrid) { + // vec2 gridRatios = GridDivider / GridSizes; + // vec2 gridThickness = abs(1.5 / GridScales / CameraZoom); + + vec4 texCoordinates = GridMatrix * modelCoordinates; + gridLinesSoft(texCoordinates.xy); + + /* + float normX = abs(modelNormal.x); + float normY = abs(modelNormal.y); + float normZ = abs(modelNormal.z); + + float gridThickness = GridSize < 4 ? 0.25 : 0.5; + float gridRatio = 1.0 / GridSize; + vec2 baseCoords; // coordinates used for overlay creation + + if (normX > normY) { + if (normX > normZ) + baseCoords = modelCoordinates.yz; + else + baseCoords = modelCoordinates.xy; + } else if (normY > normZ) { + baseCoords = modelCoordinates.xz; + } else { + baseCoords = modelCoordinates.xy; + } + + gridLinesSoft(baseCoords, gridRatio, gridThickness); + */ + } +} \ No newline at end of file diff --git a/tools/trenchbroom/shader/UVView.vertsh b/tools/trenchbroom/shader/UVView.vertsh new file mode 100644 index 0000000..e852268 --- /dev/null +++ b/tools/trenchbroom/shader/UVView.vertsh @@ -0,0 +1,34 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform vec4 Color; + +varying vec4 modelCoordinates; +varying vec3 modelNormal; +varying vec4 faceColor; + +void main(void) { + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; + gl_TexCoord[0] = gl_MultiTexCoord0; + modelCoordinates = gl_Vertex; + modelNormal = gl_Normal; + faceColor = Color; +} \ No newline at end of file diff --git a/tools/trenchbroom/shader/VaryingPC.fragsh b/tools/trenchbroom/shader/VaryingPC.fragsh new file mode 100644 index 0000000..5974e25 --- /dev/null +++ b/tools/trenchbroom/shader/VaryingPC.fragsh @@ -0,0 +1,34 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform bool ApplyTinting; +uniform vec4 TintColor; + +varying vec4 vertexColor; + +void main() { + gl_FragColor = vertexColor; + + if (ApplyTinting) { + gl_FragColor = vec4(gl_FragColor.rgb * TintColor.rgb * TintColor.a, gl_FragColor.a); + gl_FragColor = clamp(2.0 * gl_FragColor, 0.0, 1.0); + } +} diff --git a/tools/trenchbroom/shader/VaryingPC.vertsh b/tools/trenchbroom/shader/VaryingPC.vertsh new file mode 100644 index 0000000..9e2daa3 --- /dev/null +++ b/tools/trenchbroom/shader/VaryingPC.vertsh @@ -0,0 +1,27 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +varying vec4 vertexColor; + +void main(void) { + vertexColor = gl_Color; + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; +} diff --git a/tools/trenchbroom/shader/VaryingPUniformC.vertsh b/tools/trenchbroom/shader/VaryingPUniformC.vertsh new file mode 100644 index 0000000..3e4678f --- /dev/null +++ b/tools/trenchbroom/shader/VaryingPUniformC.vertsh @@ -0,0 +1,29 @@ +#version 120 + +/* + Copyright (C) 2010 Kristian Duske + + This file is part of TrenchBroom. + + TrenchBroom is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TrenchBroom is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TrenchBroom. If not, see . + */ + +uniform vec4 Color; + +varying vec4 vertexColor; + +void main(void) { + vertexColor = Color; + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; +} diff --git a/tools/trenchbroom/styles/qwindowsvistastyle.dll b/tools/trenchbroom/styles/qwindowsvistastyle.dll new file mode 100644 index 0000000..c97acd6 Binary files /dev/null and b/tools/trenchbroom/styles/qwindowsvistastyle.dll differ diff --git a/tools/trenchbroom/stylesheets/base.qss b/tools/trenchbroom/stylesheets/base.qss new file mode 100644 index 0000000..726b549 --- /dev/null +++ b/tools/trenchbroom/stylesheets/base.qss @@ -0,0 +1,40 @@ +QTableView { + border: none; +} + +QListWidget { + border: none; +} + +QListWidget#controlListBox_listWidget { + border: none; +} + +QCheckBox#entityDefinition_checkboxWidget { + margin-left: 11px; +} + +QToolButton#backgroundChecked { + border: none; +} + +QToolButton#backgroundChecked::checked { + background-color: rgba(0, 0, 0, 50); +} + +QToolButton#toolButton_withBorder { + border: 1 solid rgba(0, 0, 0, 50); + border-radius: 3; +} + +QToolButton#toolButton_withBorder::checked { + background-color: rgba(0, 0, 0, 25); +} + +QToolButton#toolButton_borderless { + border: none; +} + +QToolButton#toolButton_borderless::menu-indicator { + image: none; +} diff --git a/tools/trenchbroom/tiff.dll b/tools/trenchbroom/tiff.dll new file mode 100644 index 0000000..931c5a4 Binary files /dev/null and b/tools/trenchbroom/tiff.dll differ diff --git a/tools/trenchbroom/tinyxml2.dll b/tools/trenchbroom/tinyxml2.dll new file mode 100644 index 0000000..c45036b Binary files /dev/null and b/tools/trenchbroom/tinyxml2.dll differ diff --git a/tools/trenchbroom/zlib1.dll b/tools/trenchbroom/zlib1.dll new file mode 100644 index 0000000..6ddfd45 Binary files /dev/null and b/tools/trenchbroom/zlib1.dll differ