From d48ac4ec0cc4a8ae3bc7392f4126ef9ab024851a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Geyelin?= Date: Sun, 1 Nov 2020 18:49:17 +0100 Subject: [PATCH] Added helpers. --- content/levels/useful_helpers/graphics.lua | 9 ++ .../useful_helpers/helpers/angle_helpers.lua | 11 ++ .../helpers/boxes/box_graphics.lua | 13 ++ .../helpers/boxes/box_template.lua | 66 +++++++++ .../helpers/boxes/cannon_box.lua | 68 +++++++++ .../helpers/boxes/cannon_pickup_sound.lua | 7 + .../helpers/boxes/inner_box_graphics.lua | 52 +++++++ .../helpers/boxes/shield_box.lua | 41 ++++++ .../helpers/boxes/shield_pickup_sound.lua | 7 + .../useful_helpers/helpers/color_helpers.lua | 31 ++++ .../helpers/floating_message.lua | 26 ++++ .../useful_helpers/helpers/mesh_helpers.lua | 132 ++++++++++++++++++ .../useful_helpers/helpers/player_helpers.lua | 118 ++++++++++++++++ .../useful_helpers/helpers/sound_parser.lua | 52 +++++++ content/levels/useful_helpers/level.lua | 45 ++++++ content/levels/useful_helpers/manifest.json | 6 + docs/raw_documentation.js | 49 ++++++- server.go | 3 +- 18 files changed, 734 insertions(+), 2 deletions(-) create mode 100644 content/levels/useful_helpers/graphics.lua create mode 100644 content/levels/useful_helpers/helpers/angle_helpers.lua create mode 100644 content/levels/useful_helpers/helpers/boxes/box_graphics.lua create mode 100755 content/levels/useful_helpers/helpers/boxes/box_template.lua create mode 100644 content/levels/useful_helpers/helpers/boxes/cannon_box.lua create mode 100644 content/levels/useful_helpers/helpers/boxes/cannon_pickup_sound.lua create mode 100644 content/levels/useful_helpers/helpers/boxes/inner_box_graphics.lua create mode 100644 content/levels/useful_helpers/helpers/boxes/shield_box.lua create mode 100644 content/levels/useful_helpers/helpers/boxes/shield_pickup_sound.lua create mode 100644 content/levels/useful_helpers/helpers/color_helpers.lua create mode 100644 content/levels/useful_helpers/helpers/floating_message.lua create mode 100644 content/levels/useful_helpers/helpers/mesh_helpers.lua create mode 100644 content/levels/useful_helpers/helpers/player_helpers.lua create mode 100644 content/levels/useful_helpers/helpers/sound_parser.lua create mode 100644 content/levels/useful_helpers/level.lua create mode 100755 content/levels/useful_helpers/manifest.json diff --git a/content/levels/useful_helpers/graphics.lua b/content/levels/useful_helpers/graphics.lua new file mode 100644 index 0000000..dfb8175 --- /dev/null +++ b/content/levels/useful_helpers/graphics.lua @@ -0,0 +1,9 @@ +local helper = require("/dynamic/helpers/mesh_helpers.lua") + +meshes = {{ + vertexes = {{0,0}, {0,300}, {300,300}, {300,0}}, + segments = {{0,1,2,3,0}}, + colors = {0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff} +}} + +helper.add_vertical_cylinder_to_mesh(meshes[1], {150,150,-200}, 400, 400, 100, 0xff0000ff) diff --git a/content/levels/useful_helpers/helpers/angle_helpers.lua b/content/levels/useful_helpers/helpers/angle_helpers.lua new file mode 100644 index 0000000..e535af4 --- /dev/null +++ b/content/levels/useful_helpers/helpers/angle_helpers.lua @@ -0,0 +1,11 @@ +local helpers = {} + +function helpers.random_angle() + return fmath.random_fixedpoint(0fx, fmath.tau()) +end + +function helpers.angle_from_ratio_of_tau(numerator, denominator) + return fmath.tau() * fmath.from_fraction(numerator, denominator) +end + +return helpers \ No newline at end of file diff --git a/content/levels/useful_helpers/helpers/boxes/box_graphics.lua b/content/levels/useful_helpers/helpers/boxes/box_graphics.lua new file mode 100644 index 0000000..bca8b6a --- /dev/null +++ b/content/levels/useful_helpers/helpers/boxes/box_graphics.lua @@ -0,0 +1,13 @@ +local helpers = require("/dynamic/helpers/mesh_helpers.lua") + +function create_box(color) + local mesh = helpers.new_mesh() + helpers.add_vertical_cylinder_to_mesh(mesh, {0,0,0}, 40, 22, 7, color) + return mesh +end + +meshes = { + create_box(0xffff00ff), -- Yellow box (used by the Shield box) + create_box(0xffffffff), -- White box (used by the Shoot box) +} + diff --git a/content/levels/useful_helpers/helpers/boxes/box_template.lua b/content/levels/useful_helpers/helpers/boxes/box_template.lua new file mode 100755 index 0000000..a1d771e --- /dev/null +++ b/content/levels/useful_helpers/helpers/boxes/box_template.lua @@ -0,0 +1,66 @@ + +local box = {} + +--- Creates and returns a new box. +-- @param x fixedpoint: The x location of the center of the box. +-- @param y fixedpoint: The y location of the center of the box. +-- @param outer_mesh_info table: Contains the path to the main mesh of the box, and its index. +-- @param inner_mesh_info table: Contains the path to the inner mesh of the box that spins, and its index. +-- @param collision_callback function: The callback called when the ship of a player takes the box. Receives in argument the player's index and the ship's EntityId. +-- @param expiration int: The duration in game ticks of the bonus. If nil, the bonus lasts forever. +function box.new(x, y, outer_mesh_info, inner_mesh_info, collision_callback, expiration) + if expiration == nil then + expiration = -1 + end + + -- Create the main entity: it responds to collisions, holds the outer_mesh. + local id = pewpew.new_customizable_entity(x, y) + pewpew.customizable_entity_start_spawning(id, 15) + pewpew.customizable_entity_set_mesh(id, outer_mesh_info[1], outer_mesh_info[2]) + pewpew.entity_set_radius(id, 20fx) + + -- Create the secondary entity. It holds the inner_mesh and rotates. + local inner_mesh_id = pewpew.new_customizable_entity(x, y) + pewpew.customizable_entity_set_mesh(inner_mesh_id, inner_mesh_info[1], inner_mesh_info[2]) + pewpew.customizable_entity_set_mesh_z(inner_mesh_id, 10fx) + local inner_mesh_angle = 0fx + + local function collision_callback_wrapper(player_id, ship_id) + -- Remove the update callback to stop the rotation of the inner_mesh. + pewpew.entity_set_update_callback(id, nil) + -- Start the explosion + pewpew.customizable_entity_start_exploding(inner_mesh_id, 40) + pewpew.customizable_entity_start_exploding(id, 30) + -- Notify about the collision + if collision_callback ~= nil then + collision_callback(player_id, ship_id) + collision_callback = nil + end + end + pewpew.customizable_entity_set_player_collision_callback(id, collision_callback_wrapper) + + local function update_callback() + inner_mesh_angle = inner_mesh_angle + 0.409fx + pewpew.customizable_entity_set_mesh_angle(inner_mesh_id, inner_mesh_angle, 1fx, 0.2047fx, 0.1365fx) + if expiration > 0 then + expiration = expiration - 1 + if expiration < 180 then -- start to fade out the bonus + local alpha = (expiration * 255) // 180 + local color = 0xffffff00 + alpha + pewpew.customizable_entity_set_mesh_color(id, color) + pewpew.customizable_entity_set_mesh_color(inner_mesh_id, color) + if expiration == 0 then + -- because of a bug in PewPew 0.0.83 and earlier, you must not destroy + -- the entity immediately because of the arrow pointing to it. + -- pewpew.entity_destroy(id) + pewpew.customizable_entity_start_exploding(id, 1) + pewpew.entity_destroy(inner_mesh_id) + end + end + end + end + pewpew.entity_set_update_callback(id, update_callback) + return id +end + +return box diff --git a/content/levels/useful_helpers/helpers/boxes/cannon_box.lua b/content/levels/useful_helpers/helpers/boxes/cannon_box.lua new file mode 100644 index 0000000..cf9975e --- /dev/null +++ b/content/levels/useful_helpers/helpers/boxes/cannon_box.lua @@ -0,0 +1,68 @@ +local box = require("/dynamic/helpers/boxes/box_template.lua") +local floating_message = require("/dynamic/helpers/floating_message.lua") +local player_helpers = require("/dynamic/helpers/player_helpers.lua") + + +local cannon_box = {} + +function cannon_box.new(x, y, type) + + local duration = 100 + + local frequency + local cannon_type + local frame + local explosion_color + local msg + + if type == 0 then + frequency = pewpew.CannonFrequency.FREQ_15 + cannon_type = pewpew.CannonType.TRIPLE + frame = 1 + explosion_color = 0x00ffffff + msg = "Triple" + elseif type == 1 then + frequency = pewpew.CannonFrequency.FREQ_30 + cannon_type = pewpew.CannonType.DOUBLE_SWIPE + frame = 2 + explosion_color = 0xff8080ff + msg = "Double swipe" + elseif type == 2 then + frequency = pewpew.CannonFrequency.FREQ_3 + cannon_type = pewpew.CannonType.HEMISPHERE + frame = 3 + explosion_color = 0xffff00ff + msg = "Hemisphere" + elseif type == 3 then + frequency = pewpew.CannonFrequency.FREQ_15 + cannon_type = pewpew.CannonType.SINGLE + frame = 4 + explosion_color = 0x8020ffff + msg = "AK-286" + elseif type == 4 then + frequency = pewpew.CannonFrequency.FREQ_15 + cannon_type = pewpew.CannonType.DOUBLE + frame = 1 + explosion_color = 0xff0000ff + msg = "Double" + else + return + end + + pewpew.play_sound("/dynamic/helpers/boxes/bonus_spawn.lua", 0, x, y) + + local b = box.new(x, y, {"/dynamic/helpers/boxes/box_graphics.lua", 1}, {"/dynamic/helpers/boxes/inner_box_graphics.lua", frame}, + function(player_id, entity_id) + pewpew.configure_player_ship_weapon( + entity_id, {frequency = frequency, cannon = cannon_type, duration = duration}) + pewpew.play_sound("/dynamic/helpers/boxes/cannon_pickup_sound.lua", 0, x, y) + pewpew.create_explosion(x, y, 0xffffffff, 1fx, 20) + pewpew.create_explosion(x, y, explosion_color, 0.4000fx, 20) + floating_message.new(x, y, msg, 1.2048fx, explosion_color, 4) + end, 400) + player_helpers.add_arrow(b, 0xffffffff) + + return b +end + +return cannon_box \ No newline at end of file diff --git a/content/levels/useful_helpers/helpers/boxes/cannon_pickup_sound.lua b/content/levels/useful_helpers/helpers/boxes/cannon_pickup_sound.lua new file mode 100644 index 0000000..8770cb9 --- /dev/null +++ b/content/levels/useful_helpers/helpers/boxes/cannon_pickup_sound.lua @@ -0,0 +1,7 @@ +require("/dynamic/helpers/sound_parser.lua") + +sound = parseSound('https://pewpew.live/jfxr/index.html#%7B%22_version%22%3A1%2C%22_name%22%3A%22Powerup%2030%22%2C%22_locked%22%3A%5B%5D%2C%22sampleRate%22%3A44100%2C%22attack%22%3A0.008769257937429664%2C%22sustain%22%3A0.1%2C%22sustainPunch%22%3A70%2C%22decay%22%3A0.3797596652271855%2C%22tremoloDepth%22%3A0%2C%22tremoloFrequency%22%3A10%2C%22frequency%22%3A1500%2C%22frequencySweep%22%3A1200%2C%22frequencyDeltaSweep%22%3A1600%2C%22repeatFrequency%22%3A14.558822107330508%2C%22frequencyJump1Onset%22%3A33%2C%22frequencyJump1Amount%22%3A100%2C%22frequencyJump2Onset%22%3A100%2C%22frequencyJump2Amount%22%3A-35%2C%22harmonics%22%3A0%2C%22harmonicsFalloff%22%3A0.5%2C%22waveform%22%3A%22square%22%2C%22interpolateNoise%22%3Atrue%2C%22vibratoDepth%22%3A0%2C%22vibratoFrequency%22%3A10%2C%22squareDuty%22%3A65%2C%22squareDutySweep%22%3A20%2C%22flangerOffset%22%3A0%2C%22flangerOffsetSweep%22%3A0%2C%22bitCrush%22%3A16%2C%22bitCrushSweep%22%3A0%2C%22lowPassCutoff%22%3A22050%2C%22lowPassCutoffSweep%22%3A0%2C%22highPassCutoff%22%3A0%2C%22highPassCutoffSweep%22%3A0%2C%22compression%22%3A1%2C%22normalization%22%3Atrue%2C%22amplification%22%3A60%7D') + +sounds = { + sound +} \ No newline at end of file diff --git a/content/levels/useful_helpers/helpers/boxes/inner_box_graphics.lua b/content/levels/useful_helpers/helpers/boxes/inner_box_graphics.lua new file mode 100644 index 0000000..d06c942 --- /dev/null +++ b/content/levels/useful_helpers/helpers/boxes/inner_box_graphics.lua @@ -0,0 +1,52 @@ +local helpers = require("/dynamic/helpers/mesh_helpers.lua") + +function create_shield_inner_mesh() + local mesh = {} + local a = 3 + local b = 10 + local c = 0xffff00ff + mesh.vertexes = { + {b, -a}, {b, a}, {a, a}, {a, b}, {-a, b}, {-a, a}, {-b, a}, {-b, -a}, {-a, -a}, {-a, -b}, + {a, -b}, {a, -a}, + } + mesh.segments = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0}} + mesh.colors = c + return mesh +end + +function create_hemisphere_mesh() + local mesh = helpers.new_mesh() + local number_of_points = 10 + local radius = 10 + local compute = function(i) + local angle = (i - 1) * math.pi / number_of_points + return {math.cos(angle) * radius, -5 + math.sin(angle) * radius}, 0xffff00ff + end + helpers.add_computed_segments_to_mesh(mesh, number_of_points, compute, false) + return mesh +end + +meshes = { + -- The + in the ShieldBox + create_shield_inner_mesh(), -- The ✚ in the health box + { + -- The + bullet in the shoot box + vertexes = {{-8, 0}, {8, 0}, {0, -8}, {0 ,8}, {0,0,-8}, {0,0,8}}, + segments = {{0, 1}, {2,3}, {4,5}}, + colors = 0x11ffeeff + }, + { + -- The ◇ bullet in the shoot box + vertexes = {{8, 0}, {0, 6}, {-8, 0}, {0, -6}, {0, 0, 6}}, + segments = {{0, 1, 2, 3, 0}, {0, 4, 2}}, + colors = 0xff4040ff + }, + create_hemisphere_mesh(), -- The hemisphere icon for shoot box + { + -- three horizontal lines in the shoot box + vertexes = {{-10, -6}, {10, -6}, {-10, 6}, {10, 6}, {-10, 0}, {10, 0}}, + segments = {{0, 1}, {2, 3}, {4, 5}}, + colors = 0x9030ffff + }, +} + diff --git a/content/levels/useful_helpers/helpers/boxes/shield_box.lua b/content/levels/useful_helpers/helpers/boxes/shield_box.lua new file mode 100644 index 0000000..581ac05 --- /dev/null +++ b/content/levels/useful_helpers/helpers/boxes/shield_box.lua @@ -0,0 +1,41 @@ +local box = require("/dynamic/helpers/boxes/box_template.lua") +local floating_message = require("/dynamic/helpers/floating_message.lua") +local player_helpers = require("/dynamic/helpers/player_helpers.lua") + +local shield_box = {} + +function shield_box.new(x, y, resurrection_weapon_config) + local b = box.new(x, y, {"/dynamic/helpers/boxes/box_graphics.lua", 0}, {"/dynamic/helpers/boxes/inner_box_graphics.lua", 0}, function(player_id, ship_id) + pewpew.play_sound("/dynamic/helpers/boxes/shield_pickup_sound.lua", 0, x, y) + pewpew.create_explosion(x, y, 0xffff00ff, 0.4000fx, 40) + + if pewpew.get_number_of_players() > 1 then -- try to resurrect + local players_that_lost = {} + for i = 0, pewpew.get_number_of_players() - 1 do + if i ~= player_id then + local conf = pewpew.get_player_configuration(i) + if conf.has_lost == true then + players_that_lost[#players_that_lost + 1] = i + end + end + end + if #players_that_lost > 0 then -- pick one player to resurrect + local index = fmath.random_int(1, #players_that_lost) + local player_id = players_that_lost[index] + local ship = player_helpers.new_player_ship(position[1], position[2], 0) + pewpew.configure_player_ship_weapon(ship, resurrection_weapon_config) + pewpew.configure_player(player_id, {has_lost = false}) + pewpew.make_player_ship_transparent(ship, 120) + local new_message = floating_message.new(x, y, "reinstantiation", 2fx, 0xffff00ff, 3) + new_message.dz = 10 + new_message.dalpha = 3 + return + end + end + local conf = pewpew.get_player_configuration(player_id) + pewpew.configure_player(player_id, {shield = conf.shield + 1}) + -- local new_message = floating_message.new(x, y, "Shield +1", 1.5, 0xffff00ff, 3) + end, 400) +end + +return shield_box \ No newline at end of file diff --git a/content/levels/useful_helpers/helpers/boxes/shield_pickup_sound.lua b/content/levels/useful_helpers/helpers/boxes/shield_pickup_sound.lua new file mode 100644 index 0000000..e85a946 --- /dev/null +++ b/content/levels/useful_helpers/helpers/boxes/shield_pickup_sound.lua @@ -0,0 +1,7 @@ +require("/dynamic/helpers/sound_parser.lua") + +sound = parseSound('https://pewpew.live/jfxr/index.html#%7B%22_version%22%3A1%2C%22_name%22%3A%22Powerup%2057%22%2C%22_locked%22%3A%5B%5D%2C%22sampleRate%22%3A44100%2C%22attack%22%3A0%2C%22sustain%22%3A0.09%2C%22sustainPunch%22%3A40%2C%22decay%22%3A0.15%2C%22tremoloDepth%22%3A0%2C%22tremoloFrequency%22%3A10%2C%22frequency%22%3A1800%2C%22frequencySweep%22%3A800%2C%22frequencyDeltaSweep%22%3A1500%2C%22repeatFrequency%22%3A0%2C%22frequencyJump1Onset%22%3A33%2C%22frequencyJump1Amount%22%3A0%2C%22frequencyJump2Onset%22%3A66%2C%22frequencyJump2Amount%22%3A0%2C%22harmonics%22%3A0%2C%22harmonicsFalloff%22%3A0.5%2C%22waveform%22%3A%22whistle%22%2C%22interpolateNoise%22%3Atrue%2C%22vibratoDepth%22%3A0%2C%22vibratoFrequency%22%3A10%2C%22squareDuty%22%3A95%2C%22squareDutySweep%22%3A25%2C%22flangerOffset%22%3A0%2C%22flangerOffsetSweep%22%3A0%2C%22bitCrush%22%3A16%2C%22bitCrushSweep%22%3A0%2C%22lowPassCutoff%22%3A22050%2C%22lowPassCutoffSweep%22%3A0%2C%22highPassCutoff%22%3A0%2C%22highPassCutoffSweep%22%3A0%2C%22compression%22%3A1%2C%22normalization%22%3Atrue%2C%22amplification%22%3A70%7D') + +sounds = { + sound +} \ No newline at end of file diff --git a/content/levels/useful_helpers/helpers/color_helpers.lua b/content/levels/useful_helpers/helpers/color_helpers.lua new file mode 100644 index 0000000..d815ba4 --- /dev/null +++ b/content/levels/useful_helpers/helpers/color_helpers.lua @@ -0,0 +1,31 @@ +local helper = {} + +--- Returns a integer encoding a color. +-- @params r,g,b,a (integers in the [0,255] range): the red, green, blue, and alpha components of the color. +function helper.make_color(r, g, b, a) + local color = r * 256 + g + color = color * 256 + b + color = color * 256 + a + return color +end + +-- Returns an integer encoding a color +-- @params color: an existing 32 bit color. +-- @params new_alpha: the alpha value of the new color. +function helper.make_color_with_alpha(color, new_alpha) + local alpha = color % 256 + color = color - alpha + new_alpha + return color +end + +-- Returns the color as a string that can be used to colorize text. +function helper.color_to_string(color) + local s = string.format("%x", color) + while string.len(s) < 8 do + s = "0" .. s + end + return "#" .. s +end + +return helper + diff --git a/content/levels/useful_helpers/helpers/floating_message.lua b/content/levels/useful_helpers/helpers/floating_message.lua new file mode 100644 index 0000000..7b66d7a --- /dev/null +++ b/content/levels/useful_helpers/helpers/floating_message.lua @@ -0,0 +1,26 @@ +local color_helper = require("/dynamic/helpers/color_helpers.lua") + +local floating_message = {} + +function floating_message.new(x, y, text, scale, color, d_alpha) + local id = pewpew.new_customizable_entity(x, y) + local z = 0fx + local alpha = 255 + pewpew.customizable_entity_set_mesh_scale(id, scale) + + + pewpew.entity_set_update_callback(id, function() + z = z + 20fx + local color = color_helper.make_color_with_alpha(color, alpha) + local color_s = color_helper.color_to_string(color) + pewpew.customizable_entity_set_string(id, color_s .. text) + pewpew.customizable_entity_set_mesh_z(id, z) + alpha = alpha - d_alpha + if alpha <= 0 then + pewpew.entity_destroy(id) + end + end) + return id +end + +return floating_message \ No newline at end of file diff --git a/content/levels/useful_helpers/helpers/mesh_helpers.lua b/content/levels/useful_helpers/helpers/mesh_helpers.lua new file mode 100644 index 0000000..d20e09b --- /dev/null +++ b/content/levels/useful_helpers/helpers/mesh_helpers.lua @@ -0,0 +1,132 @@ +local helper = {} + +--- Creates a new empty mesh. +function helper.new_mesh() + local mesh = {} + mesh.vertexes = {} + mesh.segments = {} + mesh.colors = {} + return mesh +end + +--- Adds a line to a mesh. +-- @params mesh table: a properly formated mesh. Possibly created with `new_mesh`. +-- @params vertex table: a list of either 2D or 3D vertexes. The coordinates of the vertexes are floats. +-- @params colors table: a list of colors. There should be as many colors as there are vertexes. +-- @params close_loop boolean: whether the line should be a closed loop, with the first vertex being linked with the last vertex. +function helper.add_line_to_mesh(mesh, vertexes, colors, close_loop) + local vertex_count = #mesh.vertexes + local color_count = #mesh.colors + local segment_count = #mesh.segments + local number_of_new_segments = #vertexes - 1 + local segments = {} + + for i = 1, #vertexes do + table.insert(mesh.vertexes, vertexes[i]) + table.insert(mesh.colors, colors[i]) + end + + table.insert(segments, vertex_count) + for i = 1, number_of_new_segments do + table.insert(segments, vertex_count + i) + end + if close_loop then + table.insert(segments, vertex_count) + end + table.insert(mesh.segments, segments) +end + +--- Adds distincts segments to a mesh. +-- @params vertexes table: An array or vertexes. The vertexes {a,b,c,d} will draw 2 distinct segments: {a,b} and {c,d} +-- @params colors table: a list of colors. There should be as many colors as there are vertexes. +function helper.add_segments_to_mesh(mesh, vertexes, colors) + vertex_count = #mesh.vertexes + new_vertex_count = #vertexes + if new_vertex_count % 2 ~= 0 then + pewpew.print("Error: array's size should be even.") + return + end + + for i = 1, new_vertex_count do + table.insert(mesh.vertexes, vertexes[i]) + table.insert(mesh.colors, colors[i]) + end + + for i = 0, new_vertex_count - 1, 2 do + table.insert(mesh.segments, {vertex_count + i, vertex_count + i + 1}) + end +end + +function helper.add_computed_segments_to_mesh(mesh, number_of_points, compute_vertex_and_color, looping) + local vertex_count = #mesh.vertexes + local color_count = #mesh.colors + local segment_count = #mesh.segments + + local vertex_index = vertex_count + 1 + for i = 1, number_of_points do + local vertex, color = compute_vertex_and_color(i) + mesh.vertexes[vertex_index] = vertex + mesh.colors[vertex_index] = color + vertex_index = vertex_index + 1 + end + + local segments = {} + for i = 1, number_of_points do + table.insert(segments, vertex_count + i - 1) + end + if looping then + table.insert(segments, vertex_count) + end + table.insert(mesh.segments, segments) +end + +function helper.add_horizontal_regular_polygon_to_mesh(mesh, center, radius, number_of_points, color, angle_offset) + local compute = function(i) + local angle = (i - 1) * 2 * math.pi / number_of_points + local sin_angle, cos_angle = math.sincos(angle + angle_offset) + return {center[1] + cos_angle * radius, center[2] + sin_angle * radius, center[3]}, color + end + helper.add_computed_segments_to_mesh(mesh, number_of_points, compute, true) +end + +function helper.add_cube_to_mesh(mesh, center, side_length, color) + local half = side_length / 2 + local x = center[1] + local y = center[2] + local z = center[3] + + local a = {x - half, y - half, z - half} + local b = {x - half, y + half, z - half} + local c = {x + half, y + half, z - half} + local d = {x + half, y - half, z - half} + local e = {x - half, y - half, z + half} + local f = {x - half, y + half, z + half} + local g = {x + half, y + half, z + half} + local h = {x + half, y - half, z + half} + + helper.add_line_to_mesh(mesh, {a, b, c, d}, {color, color, color, color}, true) + helper.add_line_to_mesh(mesh, {e, f, g, h}, {color, color, color, color}, true) + + helper.add_line_to_mesh(mesh, {a, e}, {color, color}) + helper.add_line_to_mesh(mesh, {b, f}, {color, color}) + helper.add_line_to_mesh(mesh, {c, g}, {color, color}) + helper.add_line_to_mesh(mesh, {d, h}, {color, color}) +end + +function helper.add_vertical_cylinder_to_mesh(mesh, bottom_center, height, radius, number_of_points, color) + local bottom_center = {bottom_center[1], bottom_center[2] , bottom_center[3]} + local top_center = {bottom_center[1], bottom_center[2] , bottom_center[3] + height} + + local index_of_first_vertex = #mesh.vertexes + helper.add_horizontal_regular_polygon_to_mesh(mesh, bottom_center, radius, number_of_points, color, 0) + helper.add_horizontal_regular_polygon_to_mesh(mesh, top_center, radius, number_of_points, color, 0) + + -- Add the segments linking the 2 regular polygons + for i=1,number_of_points do + table.insert(mesh.segments, {index_of_first_vertex, index_of_first_vertex + number_of_points}) + index_of_first_vertex = index_of_first_vertex + 1 + end +end + +return helper + diff --git a/content/levels/useful_helpers/helpers/player_helpers.lua b/content/levels/useful_helpers/helpers/player_helpers.lua new file mode 100644 index 0000000..a72a0ad --- /dev/null +++ b/content/levels/useful_helpers/helpers/player_helpers.lua @@ -0,0 +1,118 @@ +local helper = {} + +-- center is a pair of fixed point values. +-- |i| is an integer in the range [0, number_of_players -1] +function helper.get_spawn_position(center, i) + local horizontal_offset = (-(pewpew.get_number_of_players() - 1) * 30) / 2 + (i * 30) + return {center[1] + fmath.to_fixedpoint(horizontal_offset), center[2]} +end + +helper.player_ships = {} + +-- the helper.player_ships variable needs to be containing the handles to all the ships +function helper.add_arrow(target_id, color) + for i = 1, #helper.player_ships do + local ship_id = helper.player_ships[i] + if pewpew.entity_get_is_alive(ship_id) then + pewpew.add_arrow_to_player_ship(ship_id, target_id, color) + else + helper.player_ships[i] = helper.player_ships[#player_ships] + table.remove(helper.player_ships, #helper.player_ships) + end + end +end + +function helper.new_player_ship(x, y, i) + local ship = pewpew.new_player_ship(x, y, i) + table.insert(helper.player_ships, ship) + return ship +end + +function helper.all_players_have_lost() + for i = 0, pewpew.get_number_of_players() - 1 do + if pewpew.get_player_configuration(i).has_lost == false then + return false + end + end + return true +end + +function helper.number_of_dead_players() + local n = 0 + for i = 0, pewpew.get_number_of_players() - 1 do + if pewpew.get_player_configuration(i).has_lost == true then + n = n + 1 + end + end + return n +end + +function helper.number_of_players_alive() + local n = 0 + for i = 0, pewpew.get_number_of_players() - 1 do + if pewpew.get_player_configuration(i).has_lost == false then + n = n + 1 + end + end + return n +end + +function helper.all_player_shields() + local total_shields = 0 + for i = 0, pewpew.get_number_of_players() - 1 do + total_shields = total_shields + pewpew.get_player_configuration(i).shield + end + return total_shields +end + +function helper.stop_level_if_players_lost() + -- only check once every 8 tick + if pewpew.get_time() % 8 ~= 0 then + return + end + if helper.all_players_have_lost() then + pewpew.stop_game() + end +end + +function helper.spawn_away_from_players(position_lambda) + local best_length = -1fx + local best_x = 0fx + local best_y = 0fx + for j = 1, 3 do + local current_x, current_y = position_lambda() + local current_length = 9999fx + for i = 1, #helper.player_ships do + local ship_id = helper.player_ships[i] + if pewpew.entity_get_is_alive(ship_id) then + local x, y = pewpew.entity_get_position(ship_id) + local dx = current_x - x + local dy = current_y - y + if dx < 0fx then + dx = -dx + end + if dy < 0fx then + dy = -dy + end + local manhattan_length = dx + dy + if manhattan_length < current_length then + current_length = manhattan_length + end + else + helper.player_ships[i] = helper.player_ships[#helper.player_ships] + table.remove(helper.player_ships, #helper.player_ships) + end + end + if current_length > best_length then + if current_length > 150fx then + return current_x, current_y + end + best_x = current_x + best_y = current_y + best_length = current_length + end + end + return best_x, best_y +end + +return helper diff --git a/content/levels/useful_helpers/helpers/sound_parser.lua b/content/levels/useful_helpers/helpers/sound_parser.lua new file mode 100644 index 0000000..d39adfd --- /dev/null +++ b/content/levels/useful_helpers/helpers/sound_parser.lua @@ -0,0 +1,52 @@ +function split(str, pat) + local t = {} -- NOTE: use {n = 0} in Lua-5.0 + local fpat = "(.-)" .. pat + local last_end = 1 + local s, e, cap = str:find(fpat, 1) + while s do + if s ~= 1 or cap ~= "" then + table.insert(t,cap) + end + last_end = e+1 + s, e, cap = str:find(fpat, last_end) + end + if last_end <= #str then + cap = str:sub(last_end) + table.insert(t, cap) + end + return t +end + +function parseSound(link) + local parts = split(link, '%%22') + local sound = {} + + for i = 2, #parts,2 do + local value = parts[i + 1]:sub(4, -4) + if parts[i] == 'waveform' then + value = parts[i + 2] + end + if parts[i] == 'amplification' then + value = value / 100.0 + end + if value == "true" then + value = true + end + if value == "false" then + value = false + end + sound[parts[i]] = value + end + return sound +end + +function EditedSound(sound, new_kvs) + local sound_copy = {} + for k,v in pairs(sound) do + sound_copy[k] = v + end + for k,v in pairs(new_kvs) do + sound_copy[k] = v + end + return sound_copy + end diff --git a/content/levels/useful_helpers/level.lua b/content/levels/useful_helpers/level.lua new file mode 100644 index 0000000..24eea8b --- /dev/null +++ b/content/levels/useful_helpers/level.lua @@ -0,0 +1,45 @@ +local angle_helpers = require("/dynamic/helpers/angle_helpers.lua") +local player_helpers = require("/dynamic/helpers/player_helpers.lua") +local floating_message = require("/dynamic/helpers/floating_message.lua") +local shield_box = require("/dynamic/helpers/boxes/shield_box.lua") +local cannon_box = require("/dynamic/helpers/boxes/cannon_box.lua") + +local width = 300fx +local height = 300fx +pewpew.set_level_size(width, height) + +local background = pewpew.new_customizable_entity(0fx, 0fx) +pewpew.customizable_entity_set_mesh(background, "/dynamic/graphics.lua", 0) + + +-- Create players +local weapon_config = {frequency = pewpew.CannonFrequency.FREQ_10, cannon = pewpew.CannonType.DOUBLE} +local ship = player_helpers.new_player_ship(width / 2fx, height / 2fx, 0) +pewpew.configure_player(0, {camera_distance = 50fx, shield = 3}) +pewpew.configure_player_ship_weapon(ship, weapon_config) + + +local function random_position() + return fmath.random_fixedpoint(10fx, width-10fx), fmath.random_fixedpoint(10fx, height-10fx) +end + +local time = 0 +pewpew.add_update_callback( + function() + time = time + 1 + local modulo = time % 100 + if modulo == 0 then + local x,y = random_position() + shield_box.new(x, y, weapon_config) + end + if modulo == 66 then + local x,y = random_position() + cannon_box.new(x, y, fmath.random_int(0, 4)) + end + if modulo == 33 then + local x, y = random_position() + floating_message.new(x, y - 50fx, "Hello!", 1fx, 0xffffffff, 0) + floating_message.new(x, y, "Hello!", 1fx, 0xffffffff, 8) + floating_message.new(x, y + 50fx, "Hello!", 1fx, 0xffffffff, 16) + end + end) diff --git a/content/levels/useful_helpers/manifest.json b/content/levels/useful_helpers/manifest.json new file mode 100755 index 0000000..bde2e2a --- /dev/null +++ b/content/levels/useful_helpers/manifest.json @@ -0,0 +1,6 @@ +{ + "name":"Useful helpers", + "descriptions":["Useful for powerups, graphics, sound!"], + "entry_point":"level.lua", + "rank_thresholds_1p":{"bronze":0, "silver":0, "gold":0} +} \ No newline at end of file diff --git a/docs/raw_documentation.js b/docs/raw_documentation.js index b5b186a..b2f54dc 100644 --- a/docs/raw_documentation.js +++ b/docs/raw_documentation.js @@ -200,6 +200,10 @@ var documentation = [ "type":"FixedPoint", }, { +"name":"camera_rotation_x_axis", +"type":"FixedPoint", +}, +{ "name":"move_joystick_color", "type":"Int32", }, @@ -630,6 +634,25 @@ var documentation = [ "type":"EntityId", }, ], +"func_name":"new_wary", +"comment":"Creates a new Wary at the location `x`,`y`.", +"parameters": [ +{ +"name":"x", +"type":"FixedPoint", +}, +{ +"name":"y", +"type":"FixedPoint", +}, +], +}, +{ +"return_types": [ +{ +"type":"EntityId", +}, +], "func_name":"new_ufo", "comment":"Creates a new UFO at the location `x`,`y` moving horizontaly at the speed of `dx`, and returns its entityId.", "parameters": [ @@ -763,7 +786,7 @@ var documentation = [ "return_types": [ ], "func_name":"customizable_entity_set_mesh", -"comment":"Sets the mesh of the customisable entity identified by `id` to the mesh described in the file `file_path` at the index `index`. `index` starts at 0.", +"comment":"Sets the mesh of the customisable entity identified by `id` to the mesh described in the file `file_path` at the index `index`. `index` starts at 0. If `file_path` is an empty string, the mesh is removed.", "parameters": [ { "name":"entity_id", @@ -782,6 +805,30 @@ var documentation = [ { "return_types": [ ], +"func_name":"customizable_entity_set_flipping_meshes", +"comment":"Similar to `customizable_entity_set_mesh`, but sets two meshes that will be used in alternation. By specifying 2 separate meshes, 60 fps animations can be achieved.", +"parameters": [ +{ +"name":"entity_id", +"type":"EntityId", +}, +{ +"name":"file_path", +"type":"String", +}, +{ +"name":"index_0", +"type":"Int32", +}, +{ +"name":"index_1", +"type":"Int32", +}, +], +}, +{ +"return_types": [ +], "func_name":"customizable_entity_set_mesh_color", "comment":"Sets the color multiplier for the mesh of the customisable entity identified by `id`.", "parameters": [ diff --git a/server.go b/server.go index fcdcf2c..4f86de0 100644 --- a/server.go +++ b/server.go @@ -30,7 +30,8 @@ func list(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "{\n") fmt.Fprintf(w, "name = \"%s\",\n", level.name) fmt.Fprintf(w, "author = \"%s\",\n", level.author) - fmt.Fprintf(w, "level_id = \"/dev/%s\"\n", level.directory) + fmt.Fprintf(w, "level_id = \"/dev/%s\",\n", level.directory) + fmt.Fprintf(w, "experimental = true\n") fmt.Fprint(w, "},\n") } fmt.Fprint(w, "}\n")