Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics


A member registered Aug 12, 2015 · View creator page →

Creator of

Recent community posts

No idea. This game is an output from a project where I tried making one game per day for a month (and consistently failed and had to go over deadline) and I basically only banked on the thumbnail to get attention :P I've not promoted it since and sort of forgotten it existed. So uh, to answer your question, I'd bet some mix of urban exploration or cursed artefacts...?

I'd definitely recommend updating, a lot of the changes were based on your feedback and surely you'd like to see it implemented? :)

Since you're playing on the GMS2 version (if my analysis of the footage is correct) there should be no need to move files around, just downloading the 1.0.5 version is all you'll need to do. The save file folder is the same and there's no difference in formats or anything. (You don't even need to put the game in the same location as the 1.0.4 executable)

There's no built-in "buff user" special effect type, so you'd need to add a custom one. The current buff special effect is handled in obj_battlecontrol's Step event at line 735-743, you'd copy that block to a new case in the switch statement that begins at line 780 (where effects that affect the user are handled). Just replacing the movespfx_BUFF constant in your new copy with the new constant, and changing all instances of the target variable trg to a_user in the new copy should be enough to make the code work.

Once all that is in place, just set your move's special effect to your new movespfx_BUFFUSER (and include the stat and buff tier like the existing buffs/debuffs) and you're good to go!

Interesting... well, the signpost hint (the bit under Swifthand's signature) points out their actual location, so it's partially true :P (And the other hint points out Sunshine's location, and Sunshine & Raccoon come from the same game originally)

I'm glad I could be of some help after so many years x3 I've forgotten so much about the game that I can't even dig around in the project file to find things because I don't know where to start looking anymore... (the game is so old that I didn't think about scalability or properly commenting my code)

Since you've been stuck on this puzzle in the fire area so long, I looked up the solution. The secret in the fire area is near the sign that says "Boiler Room, Do Not Enter":

The "rusted shut" message is the standard message when a door is an actual door object, but it has no destination. I might have kept some in for flavor, but it's also possible that area is meant to lead somewhere, and I just never finished that area. (All 50 Lore are in the game and obtainable, at least - I finished that part during the game's original 3-month jam development, so all secrets added after that are independent of the Lore system, which is why they're a bit thin on those things)

*looks it up*

Oh, the door being rusted shut at the end of that long lava area probably is intentional - there's all these signs warning you not to go through it before finally giving up and just saying "okay, fine, go through the door already" and then it's rusted shut for comedic effect. There's a lore right outside, so there's a proper reward for the trouble, and the room has a much higher ID than any of the other levels in the lava area, so it was added much later... I probably moved the Lore there because they were too easy to find originally.

Swifthand's message doesn't set any flags, so it's only there for the information dump (it points out two actual secret areas). iirc, my intention was that Swifthand lived before the apocalypse (it doesn't quite get across clearly as it is now since anybody could've written graffiti on a signpost at any time, but since the city is surrounded by monsters and a desert, and was thought abandoned before you meet the Shopkeeper, chances are urban exploration isn't a huge thing anymore, at least not in Columbus)

Interestingly, there's two versions of that canal room with layout differences, and the signpost and breakable path only appears in one of them. I've forgotten what the other copy of the level is for. Maybe it's the Epic Whirr flooding cutscene, or maybe there was a redesign at some point and I didn't want to risk losing the original layout if I didn't like how it turned out, so I kept a backup of the level.

Another fun fact: that level is named canal3 internally in the game sources, so you managed to guess the canonical name :P

(1 edit)

You'd do it like this:

if(argument0 >= AMP_FIRST_ENEMY){
  return global.monster_data[amp_read_var(argument0,amp_MONID),mond_SPRITE_BATTLE]
  return global.monster_data[amp_read_var(argument0,amp_MONID),mond_SPRITE_BACK]

The other thing I was vague about was where to add the back sprites. The init_monsters script has this place where we add an array of sprites for each monster:

Edit this and add a third "back" sprite after the map sprite. (Or before, if you prefer that, but then you'll need to make sure to adjust the changes I suggested for init_monster (without an "s" at the end) accordingly)

The freeze seems to be because the menu is destroyed with the default cancel, which doesn't advance the cutscene you're in. can_destroy is turned off just to prevent this by default, but you could add it in as a separate destroy script as a failsafe:

In msh_spawn_namingmenu at line 10, insert a new line:

script_destroy = csc_proceed;

Also insert the same line at line 3 in cc_shrinerename.

Now the menus should proceed the cutscene even if destroyed early.

For back sprites, there's a macro mond_SPRITE_BATTLE in init_constants. You'll want to add a new mond_SPRITE_BACK macro with an unique value, go to init_monster and add a new line after line 5:

global.monster_data[argument0,mond_SPRITE_BACK]    = argument2[2];

Now go to init_monsters and add the back sprite to the array of sprites that get passed in for all monsters.

To actually read the battle sprite, I think the cleanest approach is to edit monster_get_battlesprite. Check if the AMP-ID passed in is in the "enemy" region ( >= AMP_FIRST_ENEMY), and if so return the mond_SPRITE_BATTLE sprite, otherwise return the mond_SPRITE_BACK sprite.

Yeah, setting a flag in the menu event for selecting the starter would be the more robust option, since it will also work even if the player would release or trade away their starter, for instance - and you'd also not have to deal with extra cases for the starter's evolutions!

No, it's not normal. Are there any error messages while importing the project?

Also, make sure the compile target isn't set to "Windows (VM)", it might default to that since it's what I had selected when exporting the source file.

amp_has_monster just checks whether that AMP slot isn't empty. There's no script to check whether the player has a specific monster, so you'd need to make a new script with content along these lines:

//Returns true if the player owns at least 1 monster of the given species, false otherwise.
    if(global.active_monster_party[c,amp_MONID] == argument0){
        return true;
return false
Using that script instead of amp_has_monster should give the result you want :)
  • Strength, Dexterity, Intelligence and Faith increase the power of heavy weapons, light weapons, sorceries and healing spells, respectively.
  • Vigor, Attunement and Endurance influences maximal HP, MP and stamina.
  • Vitality influences maximal equip load.
  • Luck influences item drop rate.

There's some secondary uses as well (magical stats and luck influence elemental resistances, physical stats influence physical defenses, attunement gives you more spell slots) but those are the main uses.

Character customization data is defined in minit_title_charactercustomization (Script --> Menu System --> Menu Initialization). It uses the class data from init_player_classes (Scripts --> Data Mangling --> Player Stats), and the starting gift data is set up in the Create event of object obj_charactercustomization_setup. (The class data is used in some other places, like listing your class on the Status screen, but the starting gift data isn't, that's why the gifts are handled a bit less ceremoniously)

Damage is computed in rpg_compute_damage (Scripts --> Data Mangling --> RPG elements). It's a basic sum of ATK - DEF for all elements, the stats are set up by rpg_combat_statblock_init, and given actual values with rpg_setup_attack_stats for hitboxes. contact damage, etc., and rpg_setup_defense_stats for enemies.

The Thermal Plant and a small handful of other areas has fake walls (aka things that look like walls but are passable) so there might be a much more obscure way to reach the thing you're looking for (I have a faint memory of a gun upgrade being hidden in a large room designated as something along the lines of "the reactor" through an easy-to-miss pipe leading offscreen). I also remember there's an area reached through one of the "indoors" areas that doesn't connect to the main maze, that's probably what you're seeing. (The area has a bunch of jars, but it's mostly an excuse to respawn everything in the room you just left :P)

Rattleskull Valley used to connect to That One Level (the brutally difficult, unfair and unfun bonus level) but I moved it to a more hard-to-find location at the last moment. The area just ends in the middle of nowhere now if I recall correctly.

@ Saving Voice: [spoilers] I distinctly remember an ending post-credits scene (which I never actually made) where Cain explains to Daphne that "mom's not going to come home" and it reveals that she's his daughter (and Cain/Voice was a couple in the past that split up) and she stuck with Voice after they divorced... so saving her is probably non-canonical. Not sure if there's an actual way to save her buried in all those lines of code I haven't touched in a decade, but I suppose my patch notes know best :P

(Saving her would involve going to the Water Tower after you regain control... potentially before going back to the truck to avoid wasting time, I'd guess?)

Long time no see indeed! Years are getting shorter and shorter these days, aren't they? :P

Out-of-universe, the name is supposed to mean that you're the last great explorer (since the world ended in the apocalypse). Turns out I did a mistake picking that name, since googling "final columbus" gives you a ton of info on Super Bowl finals played in Columbus, and it just completely buries my game. That's the reason I changed the main title into "Heart of Ruin" :P

I have no immediate plans to make a remake (I barely have enough time to make new stuff, lol) but on the other hand I also have no reason not to... so we'll see what happens~

Oh, right, you probably want to remove that as well.

You'd want to edit mev_title_newgame to load the first map rather than send you to the character creation menu. Most of the "finalize creation" code is in mev_title_ccust_confirm_actually, with most of the character customization effect code in mev_title_ccust_update. You'd want to move the applicable bits of these over to the mev_title_newgame script (e.g. apply the stats you want the player to have, set up starting inventory, do a heal to the new max stats), then copy over the bits related to the room transition and remove the old transition (e.g., load starting coordinates, go to rm_ingame instead of the character editor).

(1 edit)

The player's customized graphics are set up in player_setup_skelani_parts. (Lines 33-92 reads equipment, the part before that sets up the body customizations). If you want a static player appearance, you could change this script to just set everything to a hardcoded list of body parts instead of reading the player equiment data.

To remove the skeletal system for the player entirely, you just need to remove the skelani_draw_skeleton call in the Draw event and replace it with a standard sprite drawing function (e.g. draw_self), and then replace all skelani_set_animation calls in the various player state machine scripts with functions to change the sprite instead. (When you're done, you might also want to consider removing the skelani_init call in the Create event to save on resources)

Fixed version is up! Thanks for the involuntary debug testing :3

On closer inspection, I just realized that this is a bug! The grass' drawing code uses || instead of && when doing the collision check, so essentially the player's status will always count as "in my particular patch of grass" and trigger the additional head drawing. Changing the the collision check ||s to && in obj_tallgrass_32's draw event (lines 13-16) should fix this. (obj_tallgrass_64 inherits everything from _32 so you shouldn't need to change that)

Yeah, there's a reason why you find no special code for this in the player object: it's actually the grass that handles it. Basically, the grass is in front of the player normally, but each grass object draws the top of the player after drawing itself if the player currently is colliding with it. (Basically, I use the "painter's algorithm" to make part of the player be above the grass... by just drawing it on top of the grass)

(For some reason I use dynamic rendering masks for this - I just realized that just drawing the upper half of the player's sprite with draw_sprite_part would've probably done the same thing but with much simpler code... x3)

(1 edit)

Nothing like a good ol' 3-year-break to get over the frustration with inescapable areas, huh? Better luck this time! :3

Most of the super-secret areas were added after I'd already ran out of lore to place (I decided to limit myself to 50 for a reason... which I've now forgotten) so most of them only house the gun upgrades (and powerups/money), the majority of all lore is on the critical path or in "regular-secret" areas. But combing the game for all the secrets hopefully feels worth it regardless~

(2 edits)

Usually my support isn't that quick, I only check my itchio messages once per day... you just got lucky and posted that thing just a couple minutes before I happened to log in, gg :P

For evolution moves, it's going to be a bit messier since I didn't consider it when making the engine, but here's my idea:

In obj_evolutioncontrol, at line 73, add some extra code that checks if the newly evolved species (targevo) has any innate moves learned at level NONE. (Those are the moves they always know regardless of level). If there's any, attempt to learn them. The code of obj_battlecontrol's step event case 32 which handles newly learned moves (around line 1010) should be a good starting point for this new code (alongside with the code that sets the movelearn queue around line 997). It might be easier to add a new state to the evolution control's step event than trying to cram all this into case 20 where it waits for the menu objects to be done, just like how battle control uses one state to populate a queue and another state to read the next entry from the queue until it's empty.

With this system in place, you can define new moves learned on-evolution by adding innate moves to the evolved monsters which are learned on level NONE.

If you think the "level NONE" thing is a bit hacky and you want to fully separate always-known moves from on-evolution moves, add a new constant ON_EVO which is a value higher than your max level (e.g. 1000) and check for moves learned on that level in the evolution control instead of moves learned at level NONE. These moves can't be learned through levelling up, since the monster can't reach past the max level, so only the special case in the evolution control will do anything with the data.

(1 edit)

Evolutions transcendences are defined at Scripts-->Data Mangling-->Database Setup-->Init Monsters, if you scroll to the right a whole bit you'll see this data:

(Basically it's an array of 3-member arrays, which represent the way to evolve, what thing triggers the evolution, and what monster to evolve to. For level evolutions, the trigger is the level to evolve at, for item evolutions it'd be the item ID, and so on... I'm unsure if I ever made item evolutions)

amp_clear_monster deletes a monster from the Active Monster Party (which is the big array that has all the monsters the player owns, including the storage boxes). Then you could use amp_generate_monster to create a new monster on the same AMP-ID, so it takes the exact slot the traded monster occupied. (Actually, you could just amp_generate_monster onto that slot directly, it clears the data with amp_clear_monster first). Once the monster is generated, you can manually apply unique quirks you want the traded monster to have (e.g. special moves or held items).

To get the AMP-ID of the monster to trade, I'd spawn a menu using msh_spawn_monster_list (which spawns a list of the monsters in the active party) which has a new "trade offer" menu event... it'd check if the monster in that slot matches what the NPC wants (that data would be stored in some global variables in the cutscene initialization script with the conversation) and if so, asks you a "ok?" question with msh_areyousure, and its OK script initiates the trade (sets the appropriate "trade done" flag, loads a different room with the trade animation, and then goes back).

If you need to familiarize yourself with how to carry data around, starting from mev_pause_monsters and looking into how the menus read party data further down the line should give you a good starting point in figuring out how to handle the AMP data (and the menu system in general).

It's sad to see things like this still are allowed to happen in 2020. I feel guilty by extension for making police-themed games, but hopefully they could act as some sort of reminder that the police is supposed to protect people, not oppress them.

Interesting results... my gut instinct would be that the bottleneck is RAM, then... it's usually easier to congest your RAM than your CPU these days. Most of the overhead is the sheer number of instances, not the heavy computations they do (some basic trigonometry and movement) so that checks out as a RAM issue in theory as well. CPU-->GPU transfer might be an issue since I don't really buffer anything particularly optimizedly, but the drawing code is pretty basic so I'm more inclined to think it's RAM transfer speeds.

The store is very much necessary, and you can access it just by diving into it (hold Z to go underwater). Didn't really have enough time to make a proper tutorial, only the button prompts on the titlescreen, so I'm kiiiiiiinda expecting everyone to read and memorize it :P

Things drawing offscreen is handled automatically, the big resource hog probably is the movement processing (since the game is on a looping arena, I need to loop through everything to see if it needs to loop around - in fact, the shark always stays still in the center of the room and I move everything else around). Not shooting any of the boat riders will tank performance a lot since they tend to shoot a lot (and overall shooting keeps the enemies culled much better than your dash will since you can hit stuff at a much greater range).

Again, it's just a simple jam game, and performance + tutorialization wasn't really a top priority... but thanks for the feedback in either case~ I'll see if I can tweak something in a post-jam version.

If you have any more questions about how to use it, you know where to find me :3

Changing resolution should be fairly trivial, the battle controller sets things up based on the room size and most menus are defined in terms of two constants VIEW_W / VIEW_H. You'll need to manually change room sizes / viewports of every room in the game, but there's just a handful of rooms so it's hopefully not too much work.

Overworld character speed is defined in pixels per step, but it's just one variable you need to change in the player's create event. You might potentially also want to change the TILESIZE constant if you change the tileset size (this will have some ripple effects like grid sizes in existing rooms also having a different size, but I've never really tried changing a tileset size so I'm not 100% sure how much of that is automated)

Attack animations uses any object you want (typically a child of the effect parent), the battle flow waits until all effects are gone before proceeding. There's a convenience script fx_deferred_projectile which lets you spawn a standard projectile which runs another script on-hit (which works for a wide range of attacks) but you can add as intricate effects as you want if you feel like it.

The movement system isn't grid-based, but it shouldn't be too hard to add in. You'd basically turn the overworld player into a state machine with two states (idle and walking): in idle state, if any movement key is pressed, if whatever's one tile in that direction is OK to stand on: switch to walking state, start a countdown of TILESIZE, and start moving in that direction. In walking state, reduce the countdown, and when it hits zero, stop moving and switch back to idle state.

Thanks for the kind words, and I'm glad you're enjoying the game! There's no feeling quite as enjoyable as watching somebody play your game for the first time (even if it made me realize all sorts of things I could've done better tutorial-wise... x3)

Thank you for the patronage and kind words! I'll be looking forward to hearing about great things from you once you get your game out there :)

There's Underwater Bubble, Waterballoon, Jump Water and Landing Water in the "modern sounds" zip, but most of the sounds are 8-bit samples that will sound nothing like realistic water.

(1 edit)

It's supposed to be in Commodore 64 style, even if it's not actually a C64 game. (I might be playing a bit fast-and-loose with system limitations like audio channels and max number of sprites per scanline, I'm not enough of a hardcore retrocomputing enthusiast to bother replicating flaws accurately...)

Thanks, it's really heartwarming to hear that! (I'm completely tone-deaf and I can't ever really tell if my music is actually good or not, so thanks for the input on that especially!) You stay safe out there too.

Hiya! Both of those names sound familiar, nice seeing you two around (and virus-safe)! Thanks for the praise and patronage, hopefully the game helps you two get through these tough times ^__^

And yeah, I'd say my biggest weakness - for all my projects - is not really having anything unique to them, especially not screenshot / box art-wise. I feel like I've got quality nailed down these days, so I probably should experiment more with trying to find something more eye-catching in style (quality is gonna be lost on people that never plays the games...). But the last year or so, I've mostly played around with learning new mechanics (and released a bunch of new engines made in the progress of that learning experience)... there's a bit of a Game Maker 3D tech arms race going on right now, spreadheaded by TheSnidr, and after dabbling with it since back in the GM6 days, I feel like I wanna be a part of making GM 3D mainstream.

All you should need to do is make the sprites bigger and edit player_free (Gameplay --> Player --> Collision Checking) to use the new sizes. The enemy counterpart uses a variable hitbox size so it should adapt automatically (if you make sure the hitbox variables are set based on the sprite size in their create event, like with all the existing enemies).

You might need to tweak movement speeds and such (defined in init_character_maria) to make the objects move at a speed that feels right for the bigger sprites too, but that's more of a "feel" thing than something absolutely necessary for it to function.

Another alternative approach that messes with gameplay even less is to edit the draw code for every object and make them draw larger sprites as x*2, y*2, but still use the 16x16 grid for collisions in reality. (Autotiled objects would create larger tiles at x2'd coordinates as well). Could get a bit messy to set up, but would let you use larger sprites without having to compensate for larger sprites gameplaywise.

(1 edit)

There's a full answer to this question in the FAQ, but to summarize it: Steam is so flooded these days that I think it wouldn't be worth the effort to make a release there for me right now (there's a $100 fee and a lot of paperwork involved in getting a game on there). If I ever get a reason to change my mind (e.g. I get a big enough following that I believe people will actually find the game, or Steam starts actually having quality control again so it's easier to get noticed), I will mail a Steam code to everyone that bought the itchio version (and set the game up for the cross-platform purchase thing for future purchases as well).

Glad you liked it! ^__^

And yeah, the final boss is a bit cheap - it's a recycled boss from one of my bullet hell games, I didn't have enough time to make a new final boss from scratch at the end of the game jam so I took the eco-friendly option.

Draw it with draw_mode7sprite (one of the engine's scripts). The obj_antagonist draws itself that way, so you could just copy its drawing code:

(Keep in mind that it assumes the sprite's origin is in the bottom center when aligning it to the 3D world)
(2 edits)

(I'm posting this here in "general" because the Jams board rules state that only jams hosted on Itchio are allowed there. Also, I'm not involved in running the jam in any way, I just figured I'd spread the word anyway because I'm a weirdo)

The GMC Jam is one of those long-running jam events, having been around for like a decade. Not quite Ludum Dare levels of history, but hey, it's something.  And the next jam (36th) begins in less than 24 hours! If you are a Game Maker: Studio user that only are active on Itchio and forgot all about the Game Maker Community, you might wanna check it out. (Official GMC discussion topic is here.) The only really major rule is "entries must be made in some Game Maker version". It might not be as easy to join or vote as in an Itchio jam, but hey, we GM users gotta keep the tradition alive, right?

The theme hasn't been revealed yet, but everyone currently thinks it is "EVERYTHING HAS A COST" after some lucky guesses during the traditional "reveal one letter at a time" phase of hype building. (If you read this more than 16 hours after the topic was posted, the theme already was officially revealed.)

Turns out, the theme actually was EVERYTHING HAS A COST.

(1 edit)

Variable jump is handled in player_controls_y, lines 16-18. Normally looks like this:

    if(jumped && !canjump && yspeed < 0){
        yspeed *= 0.5

Not sure what could be wrong, but there's a lot of variables involved, so it's possible one of them gets changed behind your back with the new ordering of things. I think this would work just fine and with less potential for interference:

    if(p_a && yspeed < 0){
        yspeed *= 0.5

(since we know that k_a is false going into this check, we have k_a && !p_a, i.e., the jump button is currently not pressed, but it was the previous step - i.e, it was released this step. We still want to check that the player is moving upwards so that check should be left in)

(1 edit)

Thanks for the kind words! ^__^ Controls remapping could be a bit messy to lift in, since every key interaction in the game uses the input system instead of standard GM keyboard events... so if you've got five thousand keyboard events spread over every object in your game, it would be some work to refactor them all.

The options menu should be a bit easier to lift in, but there's a lot of stuff you need to lift in: all the GGUI scripts (for the menu system), the horizontal, vertical and grid menu objects (and their parents), and all the relevant menu initialization and event scripts (and also mcb_optionssettingchanged, which is run when an option-menu setting is changed). And then the options_apply() and options_save() scripts to handle the options settings themselves... Thankfully, this should be pretty easy to import with trial and error. Once you think you've imported everything you need, try running the game and browsing through the options. You should get error messages along the way if you missed any objects or variables.

The options themselves just alter global variables that the various systems use (like the music and sound-effect volume variables which are used by the bgm and sfx scripts) so it should be pretty simple to deal with and extend.