diff --git a/README.md b/README.md index 7279a7f..da0ad60 100644 --- a/README.md +++ b/README.md @@ -792,6 +792,57 @@ Hallowflame and the empty AM template come with the base cast pre-set! Feel free to reach out and suggest additional options! +### Glowing Objects +You can configure your character, their projectiles, their articles, or any other object to glow in dark areas. Adding dynamic lights to your objects requires a little bit of setup, but you'll only have to do it once. Just put these two lines into your `init.gml` file: + +```gml +dynamic_lights = undefined; +with(obj_stage_main) if("dynamic_lights" in self) other.dynamic_lights = dynamic_lights; +``` + +Now you can make any object you'd like glow when your character is in an Adventure Mode stage that supports dynamic lighting. For instance, to make Sandbert's NSpecial glow, you could put this in his `hitbox_create.gml` file: + +```gml +if(attack == AT_NSPECIAL) { + if(player_id.dynamic_lights != undefined) ds_list_add(player_id.dynamic_lights, { + on_instance: id, + burnout_speed: 0.15, + darkness_threshold: 200, + sprite: sprite_get("glow"), + image: 0, + x: x, + y: y, + xscale: 1, + yscale: 1, + x_offset: 0, + y_offset: 0, + angle: 0, + blend: c_pink, + alpha: 0.6, + }); +} +``` + +All of these values are required or you'll end up with errors. Here are what they all do: + +``` +on_instance - The Instance ID of the object this light source is attached to. +burnout_speed - How fast the light goes out when the object it's attached to disappears. Higher values disappear faster. +darkness_threshold - How dark a room's ambient lighting has to be before the object will glow. Ranges from 1 (only glows in complete darkness) to 256 (always glows). +sprite - The sprite that the glow will use. Generally this should be a circular gradient. The strength of the glow is affected by the Alpha channel of each pixel. +image - Which subimage to use of the sprite. +x & y - The position that the glow will be at on its first frame. +xscale & yscale - The visual size of the glow. +x_offset & y_offset - The glow will be automatically placed at the on_instance object's position, offset with these variables' values. +angle - The angle at which the glow sprite displays. More useful for something like a flashlight, as opposed to a typical round glow. +blend - The image_blend that will be applied to the glow sprite. Keep in mind that colour blending can only make an image darker, not lighter. +alpha - How transparent the glow will be. Lower values make the glow fainter. Ranges from 0 (no glow) to 1 (maximum glow). +``` + +Once all of these are applied, you're done! The stage will automatically handle moving the light around, keeping the list clean, etc. + +If you're familiar with manipulating Lightweight Objects, also known as Structs, that's all these are. You can save the index of the LWO before passing it into the `dynamic_lights` list if you'd like to modify it later. Doing so can allow you to change any of its properties. Changing the glow's `on_instance` to `noone` is a good way to make it fizzle out immediately. + ## Optimization Strategies The RoAAM team will continue to do our best optimizing the engine over time, however as stated in Limitations there is a lot of overhead to account for, and the mod will not run well on lower end computers. Here are a list of optimization strategies figured out during the development of Hallowflame to help lift the computational burden. diff --git a/scripts/article12_draw.gml b/scripts/article12_draw.gml index 84bc937..a0a41f9 100644 --- a/scripts/article12_draw.gml +++ b/scripts/article12_draw.gml @@ -16,6 +16,13 @@ if(!cant_root && draw) draw = false; } } + var i = 0, drawing_light; + repeat ds_list_size(player_id.dynamic_lights) { + drawing_light = player_id.dynamic_lights[| i]; + if(colour_get_value(bg_color_true) < drawing_light.darkness_threshold) + draw_sprite_ext(drawing_light.sprite, drawing_light.image, drawing_light.x, drawing_light.y, drawing_light.xscale, drawing_light.yscale, drawing_light.angle, drawing_light.blend, drawing_light.alpha); + i++; + } gpu_set_blendenable(true); gpu_set_alphatestenable(true); gpu_set_colorwriteenable(true,true,true,true); @@ -31,6 +38,13 @@ if(!cant_root && draw) //if val_limit < color_get_value(other.bg_color_true) draw_sprite_ext(render_sprite, render_index, x, y, image_xscale, image_yscale, image_angle, c_white, 1); } } + i = 0; + repeat ds_list_size(player_id.dynamic_lights) { + drawing_light = player_id.dynamic_lights[| i]; + if(colour_get_value(bg_color_true) < drawing_light.darkness_threshold) + draw_sprite_ext(drawing_light.sprite, drawing_light.image, drawing_light.x, drawing_light.y, drawing_light.xscale, drawing_light.yscale, drawing_light.angle, drawing_light.blend, drawing_light.alpha); + i++; + } gpu_set_blendmode(bm_normal); gpu_set_alphatestenable(false); draw_set_alpha(1); diff --git a/scripts/init.gml b/scripts/init.gml index f108c45..6c8831d 100644 --- a/scripts/init.gml +++ b/scripts/init.gml @@ -43,6 +43,7 @@ cam_vel_influence = 20; game_paused = false; counter = 0; +dynamic_lights = ds_list_create(); debug_console = false; debug_x = 650; diff --git a/scripts/load.gml b/scripts/load.gml index 770d768..edff2ce 100644 --- a/scripts/load.gml +++ b/scripts/load.gml @@ -116,6 +116,7 @@ sprite_change_offset("well",24, 70); sprite_change_offset("light", 39, 46); sprite_change_offset("light_dimver", 40, 49); sprite_change_offset("light_dimver_larg", 40*4, 49*3+25); +sprite_change_offset("light_sein", 40*4, 49*3+25); sprite_change_offset("enemy_10_vision", 0, 84); sprite_change_offset("house_main_inside",15, 111); sprite_change_offset("house_main_insideb",15, 111); diff --git a/scripts/other_init.gml b/scripts/other_init.gml index c7f29a9..0c61d37 100644 --- a/scripts/other_init.gml +++ b/scripts/other_init.gml @@ -96,6 +96,24 @@ switch p_name { // am_is_clothed = false; LOINCLOTH am_is_guest = false; pronouns = ["he","him","his","is"]; + + //Zetterburn glows + with(obj_stage_main) ds_list_add(dynamic_lights, { + on_instance: other, + burnout_speed: 0.15, + darkness_threshold: 200, + sprite: sprite_get("light"), + image: 0, + x: x, + y: y, + xscale: 2, + yscale: 2, + x_offset: 0, + y_offset: -30, + angle: 0, + blend: c_red, + alpha: 0.6, + }); break; //Bastard turned good boi case "Forsburn": @@ -104,6 +122,28 @@ switch p_name { // am_is_experienced = true; am_is_guest = false; pronouns = ["he","him","his","is"]; + + //Forsburn glows, but only when he's not emitting smoke + dynamic_glow = { + on_instance: id, + burnout_speed: 0.15, + darkness_threshold: 170, + sprite: asset_get("empty_sprite"), + image: 0, + x: x, + y: y, + xscale: 1.6, + yscale: 1.6, + x_offset: 0, + y_offset: -30, + angle: 0, + blend: c_orange, + alpha: 0.3, + }; + with(obj_stage_main) { + other.dynamic_glow.sprite = sprite_get("light"); //give Forsburn the sprite index (he can't use sprite_get) + ds_list_add(dynamic_lights, other.dynamic_glow); + } break; //Protagonist Prime case "Clairen": @@ -241,13 +281,37 @@ switch p_name { pronouns = ["she","her","hers","is"]; break; //Upair is a kill move - case "Ori": + case "Ori & Sein": am_is_aether = true; am_is_verbal = false; am_is_magic = true; am_is_small = true; //Cannon Ori is tiny am_is_experienced = true; //They are a leaf and I don't think we get cannonical pronouns + + //Sein glows (i think??) + var sein_id = id; + with(asset_get("orb_obj")) sein_id = self; + dynamic_glow = { + on_instance: sein_id, + burnout_speed: 0.15, + darkness_threshold: 245, + sprite: asset_get("empty_sprite"), + image: 0, + x: x, + y: y, + xscale: 0.75, + yscale: 0.75, + x_offset: 0, + y_offset: 15, + angle: 0, + blend: c_white, + alpha: 0.2, + }; + with(obj_stage_main) { + other.dynamic_glow.sprite = sprite_get("light_sein"); //give Ori the sprite index + ds_list_add(dynamic_lights, other.dynamic_glow); + } break; //???? case "Shovel Knight": diff --git a/scripts/update.gml b/scripts/update.gml index 89997c0..c2eba51 100644 --- a/scripts/update.gml +++ b/scripts/update.gml @@ -186,16 +186,60 @@ if !_init { // if state != PS_AIR_DODGE old_pos = [x,y]; // if state == PS_RESPAWN print("[update:player] completed check"); + + if(url == CH_FORSBURN) { + if(spewing_smoke) { + dynamic_glow.xscale *= 0.8; + dynamic_glow.yscale *= 0.8; + } + else { + dynamic_glow.xscale = 1.6; + dynamic_glow.yscale = 1.6; + } + } + else if(url == CH_ORI) { + if((state == PS_ATTACK_GROUND || state == PS_ATTACK_AIR) && (attack == 20 || attack == 21 || attack == 22)) + dynamic_glow.on_instance = id; //Sein's glow comes from Ori's position when using a team-up attack + else if dynamic_glow.on_instance == id with(asset_get("orb_obj")) { + other.dynamic_glow.on_instance = self; + } + } } var i = 0; - repeat ds_list_size(active_bosses) { if (!instance_exists(active_bosses[| i])) ds_list_remove(active_bosses,active_bosses[| i]); i++; } + i = 0; + repeat ds_list_size(dynamic_lights) { + if (!instance_exists(dynamic_lights[| i].on_instance)) { + if(dynamic_lights[| i].burnout_speed != undefined) { + //initialize burning out + dynamic_lights[| i].burnout_sign = -1 * sign(dynamic_lights[| i].xscale); + dynamic_lights[| i].burnout_xspeed = dynamic_lights[| i].burnout_sign * dynamic_lights[| i].burnout_speed; + dynamic_lights[| i].height_ratio = dynamic_lights[| i].yscale / dynamic_lights[| i].xscale; + dynamic_lights[| i].burnout_speed = undefined; + } + dynamic_lights[| i].xscale += dynamic_lights[| i].burnout_xspeed; + dynamic_lights[| i].yscale = dynamic_lights[| i].height_ratio * dynamic_lights[| i].xscale; + + // dynamic_lights[| i].alpha -= 2 * sign(dynamic_lights[| i].burnout_xspeed); + + if(sign(dynamic_lights[| i].xscale) == dynamic_lights[| i].burnout_sign) { + ds_list_remove(dynamic_lights,dynamic_lights[| i]); + i--; + } + } + else { + dynamic_lights[| i].x = get_instance_x(dynamic_lights[| i].on_instance) + dynamic_lights[| i].x_offset; + dynamic_lights[| i].y = get_instance_y(dynamic_lights[| i].on_instance) + dynamic_lights[| i].y_offset; + } + i++; + } + //Window Update Call win_call = 2; user_event(2); diff --git a/sprites/articles/light_sein_strip4.png b/sprites/articles/light_sein_strip4.png new file mode 100644 index 0000000..7efd788 Binary files /dev/null and b/sprites/articles/light_sein_strip4.png differ