A downloadable asset pack for Windows

Get this asset pack and 37 more for $49.99 USD
View bundle
Buy Now
On Sale!
50% Off
$14.99 $7.49 USD or more

Yal's Monster Collector Engine is a GameMaker:Studio 2 project with all the tools you need to make a monster-collector RPG in the style of Pokémon / Digimon / Temtem / Telefang. The turn-based engine is supplemented with a solid database and GUI system that lets you easily script menus and manage data.

Try out the free demo if you want a first-hand taste of all the cool stuff this engine can do! It's got close to an hour of gameplay if you take your time and explore everything! :D

Features

  • Define a monster, item, move, or other database item with a single line of code! It's super easy to add content! Items and moves are based on extensible effect structures, and the engine comes with plenty of example items, monsters and moves to play around with!
    • Databases are set up using GML scripts - easy to change, and you get tons of color coding by default!
    • Each database entry is a single line in the script! All data is in one place, and it's super easy to add new monsters, moves, types and items!
    • Non-standard functionality is handled by script references, letting you offload as many complex special cases as you need to elsewhere in the codebase, keeping the database structured and clean!
    • Cutscenes uses a similar system where you enqueue script to be executed, each one with as many arguments as is needed! Just enqueueing messages is good enough to get information across, but you can get as advanced as you want!
  • Engine back-end code is only using the most basic GML functionality (arrays, loops etc) ensuring maximal compatibility between exports, and making the code  easy to read and understand! The code is also fully commented, with special tags to point out clever hacks and other parts that needs handling with care or are sensitive to changes.
  • The battle system supports an arbitrary amount of monsters on each side in battle! Do you think 1-on-1 battles is boring? How about making 2-vs-5 battles the new standard! You can have more monsters than fits on the screen if you want!
  • Moves, capturing monsters, battles etc  handles an arbitrary amount of monsters on each side just fine! You can even set the number of monsters on each side on a battle-per-battle basis, surprising the player with a 6-vs-1 horde battle in the middle of a dungeon for some extra challenge!
  • Newly caught monsters that don't fit in your party automatically gets sent to the storage system! Easily move monsters around between the active party and a number of storage boxes! (The number of storage boxes also can be set to any number you want - default 10 boxes of 40 monsters)
  • Supports as many savefiles as you want! (Default 99)
  • Easily set up monster trainers and other NPCs right in the room editor using the new GMS2 "variables" system! You don't even need to open a code editor, you just provide some monster data and dialogue data and then it's all set!
  • The engine automatically keeps track of both items and trainers! All you need to do is place them in a room, and the game will register them as defeated / collected automatically!
  • Simple system to connect different rooms with doors - doors just use two variables: a "label", and a room to transport the player to. The player is automatically placed next to the door with the matching label! Give your doors clear names like "shrine" or "freddy's house" instead of having to worry about their coordinates with pixel perfect precision!

It's Super Effective!

  • Traditional mechanics like move types being effective against certain monster types, held items having special effects, and monster trainers fighting you with a series of extra-strong monsters all are in place, and will work out of the box!
    • The held-item system has hooks set up at several points in the combat-turn flow, allowing you to run a script there to do whatever you want! Power up a monster's attack, heal it at the end of a turn, react to an enemy's attack, and more!
    • The type system allows an arbitrary number of types with extra damage, weakened damage, or downright immunity to other types! Add in that type you always wanted in the ultimate clash of elements, or settle down for a simple system that literally uses rock, paper and scissors!
  • Catch feral monsters, level them up, and watch them learn moves and even transform into new stronger species!
    • Monsters can automatically transform into a stronger species when their level is high enough! You just need to define the bond in the monster database, the engine handles the rest!
    • Monsters learn new attacks automatically, you just need to define it in the monster database!
    • Give your monsters nicknames to make them more relatable! Won't change anything gameplaywise, but it sure is fun!
  • The GoodGUI System from Yal's SoulsVania engine makes a return, making it easier than ever before to script your own menus! Plot out frames and fill them with content, and the menu contents will stay in position even if you resize the frames later! No need to manually tweak every coordinate to pixel precision!
  • Want to make a traditional RPG but feel RPG Maker is too limited? Just dummy out the monster-catching part and you've got a powerful turn-based battle engine to play around with!
  • Comes with graphics, music, sound effects, and monster data that can be used commercially! Use the engine for whatever you want, as long as you don't resell it (or parts / derivative works of it) as an asset pack!

(Note that this project is not compatible with GameMaker Studio 1.x)


Try it out!

There's a free demo of the project showing off all the features! Explore the first area, pick a starting monster, catch and train a party of local fauna, take in the tranquility of Driftwood City, and rise to the challenge of Fielder, the first League Master!

Demo controls:

Arrows - Move around / select stuff in menus

X - Select stuff / interact

Z - Cancel

StatusReleased
CategoryAssets
Rating
Rated 4.9 out of 5 stars
(15 total ratings)
AuthorYal

Purchase

Get this asset pack and 37 more for $49.99 USD
View bundle
Buy Now
On Sale!
50% Off
$14.99 $7.49 USD or more

In order to download this asset pack you must purchase it at or above the minimum price of $7.49 USD. You will get access to the following files:

Source Code (GMS 2.3) (fixed, v.3) 26 MB
Source Code (GMS2.2) 26 MB

Download demo

Download
Demo 15 MB
Download
EULA 22 kB

Development log

Comments

Log in with itch.io to leave a comment.

Viewing most recent comments 1 to 40 of 107 · Next page · Last page

Hi Yal, during battle, if I have seperate animations designed for a specific monster, like idle, phys/mag/stat moves,  and hurt animations, how would I change the animation state, instead of the current hard coded animation? 

Also how do I make it so when a monster use a certain type of move it will play one of the three pre-done animations? 

(1 edit)

Currently, this code block in battlecontrol's step event is what actually plays the animation (using the animation object of the move). a_user is the monster object who is doing the action, and a_targ is an array of one or more monster objects that are being targeted. (And the target can contain the user, e.g. if the move is a buff or recovery action). So, this is the "entry point" where you'd want to put any new behavior.

Your question is a bit vague but I think this is what you're asking for:

  • If some monsters has special animations for certain types of moves, add a struct to the monster data which contains a list of conditional sprites for those moves, stored in a new slot mond_SPECIALANIMATIONS in the monster data array.
    • init_monster initializes the entire struct to NONE for all the cases (cases being e.g. "physical", "special" and "stat"), but then checks if the sprite argument (argument2) is longer than 2 - if so, it reads slots 2 and 3 as a parameter-sprite pair, then slots 4 and 5, and so on, and overwrites the default data in the struct.
    • In the animation entry point, the struct of the monster's special animations is checked (go through a_user --> AMP reference --> monster species ID) using the move's category (e.g. movecat_MAGIC means "special" category) and if there is an animation (i.e., the struct's value for the category is not NONE) it is used
  • To actually perform the animation, you'd set the sprite_index of the affected object to the sprite from the struct, reset image_index to 0 so it starts from the beginning, and then add a new Other --> Animation End event in the obj_battlemonster which resets the sprite to the species' default sprite (so when the animation ends, it goes back to the regular sprite).
    • (And to do custom "hurt" animations, you'd basically do the exact same thing - override the sprite when taking damage, and then the Animation End event resets it to the regular sprite)
 

You don't even need to initialize the struct to all NONE's since variable_struct_exists exists - if e.g. variable_struct_exists("physical") is false when checking the monster species' animations, you can conclude it has no special animation for physical attacks and just skip overriding its sprite.

(I'm assuming you mean "sprite animations" here but if you want attack control objects you could pretty much set up the data the same way)

(+1)

Thank you so much! I'll try it out. 

Me again yal haha, how about sistem like mega evolution. Can you give me the easy way to add it in this engine

I think the easiest way to add this would be having a new global array of "mega evolutions data" which has three items per row: base monster, mega monster, and held item needed for the transformation.

  • When generating the Moves menu, check each row of the mega evolutions data and if both the base monster and held item matches this monster's data, add a fifth option for mega evolution (unless you've already mega'd another monster in this battle, which you'd keep track of in a separate variable), picking this option will change that monster's species to the mega monster.
    • All mega IDs should be at the very end of the monster data, perhaps even beyond MONSTER_MAX so the data won't e.g. get added to the dex.
  • At the end of battle, go through the mega evolutions array again and if any of the player's party monster has a mega species, change it back to the regular species.

Another hehe, what var map mean in init_monsters script. If no use, can i use it to numbering the monster ini the dex? 

The idea was to use the map sprite as a special icon when looking at the status screen (e.g. on the map) but I ended up never using it (I did a code search and there's no hits for it) so you can go ahead and use it for whatever you want! :)

Internally it's global.monster_data[monsterID,mond_SPRITE_SMALL]  ("SPRITE_SMALL" rather than "SPRITE_MAP")

Thanks yal, two other questions again. First How to add monster owning sign at monster encounters and second how to add number sign of monster enemy trainers has in his party 

The game already keeps track of which monsters you've owned, the global.monsters_caught array (indexed by monster species ID). So for instance you could have enemy side's obj_battlemonsterhud check if global.monsters_caught[global.active_monster_party[monster.amp_id,amp_MONID]] is true (and if so, draw the "owned" icon)


You can check how many enemies are alive by running

var num_alive = 0;
for(var mon = AMP_FIRST_ENEMY; mon < AMP_FIRST_ENEMY + PARTYSIZE_MAX_ENEMY; mon++){
    if(global.active_monster_party[mon,amp_HP] > 0){
        num_alive++;
    }
}

You'd probably want to count once at the start of the battle (within bcontrolstate_ANNOUNCE_TRAINER) to get the TOTAL amount of monsters, and then count the number of currently available ones in the Draw event (so you can cross out KO'd monsters when drawing)

Thanks yal, another one how to add split evolution easily. Either with item or level

Currently evolutions already are an array, with zero or more tuples [type, parameter, evoSpecies]. For item split evolutions you could just add them there, but be triggered by different items.

For levels I'm thinking the easiest would be adding new evolution types, e.g. evotype_LEVEL_SPLIT_PHYS_ATK and evotype_LEVEL_SPLIT_DAYNIGHT_PHYS_DEF for a monster that becomes one species when its ATK is higher and another if its DEF is higher. These come in pairs (or triplets, etc), one type for each "branch" of evolution and then you'd give the monster one evolution tuple for each branch. (So e.g. [[evotype_LEVEL_SPLIT_PHYS_ATK, 10, mon_SWORDY], [evotype_LEVEL_SPLIT_DAYNIGHT_PHYS_DEF, 10, mon_SHIELDY]]  as the evolutionlist)

The script amp_earn_exp is also responsible for keeping track of pending evolutions, and currently it only checks for evotype_LEVEL here. You would add the new types here as well, but have them only enqueue the new evolution if the condition for that "branch" is met (and then make sure to write conditions so that only one can be met at a time)

Me again 😁, how about TM. How to add it easily?

I'm thinking something like this:

  • The item should be itemvalid_FIELDONLY so you can't use it in battle and have a new use_script itemuse_teachmove where the use_arg is the ID of the move.
  • The new use script should first attempt to learn it with amp_learn_move_instantly, this function returns "false" if the monster already has a full movelist and if so you'll need to create a menu. You can copy this code from obj_battlecontrol's Step Event case 32 (but in the itemusescript the AMP ID will be argument0 and the move ID will be argument1 rather than "exp_monster" and "nm").
  • Instead of using mev_monster_learnmove_spawnmenu directly, make a copy of it that, in turn, uses a copy of mev_monster_learnmove_confirm to confirm moves. This copy of the function doesn't destroy ALL parent_menu objects (we want the inventory menu and main menu to remain) but only the intermediate steps, and it also removes 1 copy of the TM (assuming you want them to be consumable and not reusable like in XY onwards). Likewise the copy of mev_monster_learnmove_cancel also lets the main and inventory menus remain.

Hai y al, me again, i want to change the player overworld sprites size to 32x32 and the tileset to, can you guide step by step so i can change it without problem on the engine. Also are this action safe? 

Overworld sprites should "just work", draw_sprite_gridbased uses a percentage of the sprite asset's size so the only thing that matters is that it's a 4x4 grid.

For the tiles, change the TILESIZE macro-constant to 32 (it's set in init_constants) and then also update the settings of tileset_indoors and tileset_outdoors to be 32 (the underlying sprites also need to be resized to 640x512 for the information about how many columns of tiles are in the sets to be accurate. 

Changing the sizes should be safe (I use the TILESIZE constant everywhere) except I don't know what Game Maker will do with pre-existing tile layers when you change the tilesize. It's probably best to make a backup of your project (File --> Export Project --> YYZ) before you do this.

Hey yals, i think i touch very important code in this engine. Maybe at priority of message script. Hmm 😢😥😭


___________________________________________

############################################################################################

ERROR in action number 1

of Destroy Event for object parent_menu:

Unable to find any instance for object index '49' name 'obj_player'

 at gml_Script_csc_proceed (line 5) -               obj_player.my_sprite = spr_player

############################################################################################

gml_Script_csc_proceed (line 5)

gml_Script_mev_messageproceed_script (line 6)

gml_Object_parent_menu_Destroy_0 (line 6)

gml_Script_message_menu_step (line 5)

gml_Object_parent_menu_Step_0 (line 10)

Can you help me? 

The error is because there's no player in the room. One way around it is to use with loops instead which does nothing if there's no object that matches it, try replacing the line with this:

with(obj_player){
    sprite_index = spr_player;
}

Hey yal. Me again, how to use key item. I need to use spesific key item so I need to call variable to that specific key item to use in script

Fundamentally, all items work the same and the category is just for sorting. You just need to give the key item a validflag for using in field, a use_script and an use_arg and it should become usable. The actual functionality would be in the use_script, and if you don't need the use_arg you can just ignore it in the script.

(Check out init_items if that explanation didn't make sense)

oh okey, can you give me example code that check if i have a 2 potion in my inventory to perform a script

I'm reading your question as "you need to find 2 separate potions to unlock a cutscene" and then you'd do something like,

if(inventory_has_item(FIRST_POTION) && inventory_has_item(SECOND_POTION)){
  csc_enqueue( ... ) //stuff from the good cutscene where you cure the sick grandma)
}
else{
  csc_enqueue( ... ) //stuff from the bad cutscene where you're told you need to find both the potions
}

If it's two of the same potion you'd use inventory_has_item(POTION,2) (it can check for specific quantity)

(+1)

thanks yal, finally work

(1 edit)

Pertanyaan lain, bagaimana cara mengatur item spesifik yang hilang setelah digunakan dengan cara yang sederhana? Saya masih belum mengerti skrip kehilangan item inventaris. Terlalu rumit bagi saya.

(+1)

nevermind fix it 😀

Hallo Yal! Just a general question, how would I go about making special move effect logics in a relatively simple way? Such as incorporating move priority, attack heals for a percentage of the damage, or (de)buffing more than one stat at a time, etc.

(1 edit)

For priority, I would add a new parameter to init_move for move priority (which is 0 for all moves that doesn't have a priority) and then when you action_slate the move, add some big number times the move's priority to the speed-priority parameter. There's three places move-actions are slated: mev_battle_attack_select, mev_battle_attack_select_target, and obj_battlecontrol's step event. (There's already cases where actions are slated with higher priority, like when using a consumable item in battle, so the only thing that's missing is a bonus priority value from the move data)

For "attack heals for a percentage of damage" I would add a new side-effect type called "movespfx_LIFESTEAL" and give to those moves, special effects are handled in obj_battlecontrol's step event (search for "mvd_SIDEEFFECT_TYPE" to find where it's processed) and this is where you'd add the logic to heal the user based on how much damage the target took (the user's ID is in a_user). You can access the amount of damage dealt through n.my_dmg (the obj_damageapply created in the Damage block) though you'd probably want to save it in its own variable that's always initialized to 0 (in case the damage block gets skipped due to the move having 0 power n.my_dmg does not exist which will lead to a game crash if you try accessing it).

For multiple buffs/debuffs i would do something similar, add new side effect types for multiple buff/debuffs, and for these the mvd_SIDEEFFECT_SUBTYPE slot of the movedata would be an array:

[50,    movespfx_MULTIDEBUFF,        [stat_DEF,stat_RES],        1]

Applying these would be very similar to the current buff/debuff code but you loop over the "stat" value (since it's an array).

...actually, you could probably just turn the regular buff/debuff cases into loops in case an array is passed into them (use is_array to check), and avoid the extra work of having separate multibuff/debuff values.

Hai yal, me again. How to easily add fishing system ini this engine? I mean not only fishing a monster but sometime  item to

If you want a Palworld-style instant success when fishing a monster, you can give the player a new monster anywhere you want by getting the first free party ID with amp_get_new_party_idamp_get_new_box_id and then use amp_generate_monster to fill it with monster data. So when you successfully clear the fishing minigame you'd do this and then show a little announcement about it.

If you instead want to trigger a battle when fishing up a monster, the code in player_step_fill shows how to trigger a random encounter (though you'd probably wanna use a different list of monsters than the area's regular encounter table when picking which monster you fight).

(1 edit)

Thanks yal.  yeah it work, but problem come when the party is full. How to fix this? Also monster nickname

For party is full, use amp_get_new_box_id to get a box slot if the party is full (amp_get_new_party_id returns NONE if there's no free slots)

Use msh_spawn_namingmenu to spawn a nickname menu. You can see how it's used in mev_battle_catch_nickname (note how it assigns the my_monster variable to the AMP slot the monster was placed in)

i still has problem with this, because I don't understand which script i used first, get monster to the party or rename it? Can you give me the example code? 

(+1)

thank yal but it fix now, i just need script to check empty party and box now

Another question, i tried to change the size of monster move bar gui at the battle but i cant find it how. Same happen with chosen gui at the shrine. Can you guide me how? 

The move list in battle is set up by mev_battle_attack.

I don't understand what you mean with "chosen GUI at the shrine" but the terminal menu is set up by msh_terminal_load_page.


Both of these have comments for what each block of code does (e.g. "Frame with type/MP info") so hopefully it should be easy to figure out how to change the parts you want to change.

Thank yal fix the gui battle move, but the gui i mean in the shrine was dialog box that pooped with option such as heal and other. I wanna to change that to

Ah, got it.

Currently it uses the cc_question cutscene command (which is shared between all multichoice questions) so my recommendation would be to copy that to a new script cc_shrinequestion and then edit that to create the menu the way you want.

Hei. Me again, what is the best way to add virtual key at this engine. I try but sometime they vanish at some place

Are you spawning the virtual keys offscreen perhaps? All of the menus draw themselves in the Draw GUI event (GUI layer) to avoid having to think about that, be careful not to use the x / y position of menu objects (which is not used) but instead check the coordinates of the GGUI frames / GGUI elements, which are in GUI coordinates.

(Also, are you using the Game Maker virtual keys system or making your own?)

(1 edit)

Any plans to update any further? Like add more features and such?

Not really, adding more features also makes it more complicated to use. (Though if you check the comments I have suggested implementations for a lot of commonly requested features)

Hey Yal can you help me with making abilities so far i have initialized them the same way you have monsters and items, but i cannot seem to understand how those work also i am having trouble drawing them in the status menu, how do i do that.

So far i have done this :

function init_ability(argument0, argument1, argument2, argument3, argument4, argument5, argument6 ,argument7) {

global.ability_data[argument0,abl_NAME ] = argument1

global.ability_data[argument0,abl_TRIGGER ] = argument2

global.ability_data[argument0,abl_TARGET1 ] = argument3[0]

global.ability_data[argument0,abl_CHANCE1 ] = argument3[1]

global.ability_data[argument0,abl_TYPE1 ] = argument3[2]

global.ability_data[argument0,abl_EFFECT1 ] = argument3[3]

global.ability_data[argument0,abl_SEVERITY1 ] = argument3[4]

global.ability_data[argument0,abl_TARGET2 ] = argument4[0]

global.ability_data[argument0,abl_CHANCE2 ] = argument4[1]

global.ability_data[argument0,abl_TYPE2 ] = argument4[2]

global.ability_data[argument0,abl_EFFECT2 ] = argument4[3]

global.ability_data[argument0,abl_SEVERITY2 ] = argument4[4]

global.ability_data[argument0,abl_WEAKNESS1 ] = argument5[0]

global.ability_data[argument0,abl_WEAKNESS2 ] = argument5[1]

global.ability_data[argument0,abl_WEAKNESS3 ] = argument5[2]

global.ability_data[argument0,abl_IMMUNITIES1 ] = argument6[0]

global.ability_data[argument0,abl_IMMUNITIES2 ] = argument6[1]

global.ability_data[argument0,abl_IMMUNITIES3 ] = argument6[2]

global.ability_data[argument0,abl_STRENGTHEN1 ] = argument7[0]

global.ability_data[argument0,abl_STRENGTHEN2 ] = argument7[1]

global.ability_data[argument0,abl_STRENGTHEN3 ] = argument7[2]

}

/// init_abilities()

function init_abilities() {

init_ability(abl_FLAMECLOAK, "Flame Cloak", EMERGE,

[movetarg_USER, 100, type_FIRE, ailment_BURN, 1],

[NONE,NONE,NONE,NONE,NONE],

[NONE,NONE,NONE],

[NONE,NONE,NONE],

[NONE,NONE,NONE]

);

}

#region//ability region

#macro abl_NAME 1

#macro abl_TRIGGER 2

#macro abl_TARGET1 3

#macro abl_CHANCE1 4

#macro abl_TYPE1 5

#macro abl_EFFECT1 6

#macro abl_SEVERITY1 7

#macro abl_TARGET2 8

#macro abl_CHANCE2 9

#macro abl_TYPE2 10

#macro abl_EFFECT2 11

#macro abl_SEVERITY2 12

#macro abl_WEAKNESS1 13

#macro abl_WEAKNESS2 14

#macro abl_WEAKNESS3 15

#macro abl_IMMUNITIES1 16

#macro abl_IMMUNITIES2 17

#macro abl_IMMUNITIES3 18

#macro abl_STRENGTHEN1 19

#macro abl_STRENGTHEN2 20

#macro abl_STRENGTHEN3 21

#endregion

I think the easiest way to figure out how to implement abilities would be running a search (Ctrl+Shift+F) for itemvalidflag_AUTO_, this should bring up all the places where items are automatically triggered (e.g. the Spiked Shell being triggered on damage to deal a counter attack... you'd want a similar check for abilities being triggered on damage at basically the same place, for things like Flash Fire, Sturdy and so on; other abilities might trigger on each turn, or when attacking, etc)

You'll also need to actually give abilities to monsters (so init_monster needs to take a new argument for ability, the global.monster_data array be extended so it can fit this new data in, and the giant setup in init_monsters should provide it of course)

To show the ability, mev_pause_monsters_status is the script that builds the status screen. You'd read out the abl_NAME field here and create a ggui_element_text to display it somewhere.

Hey Yal, can you help me with a few things : 

1.How can I delete save files

2.How do i enable double battles for certain trainers

3.How do i set encounters for the room, i found ects_placeholder() but I could not find out how it applied and how to make more

thank you

1) Savefiles are found in AppData/Local/<name you saved the GM project under>, monster_save0 is the first file, monster_save1 the second and so on. It's a hidden folder so the easiest way to find it is to type in %LOCALAPPDATA% in the file explorer path and hit enter.

2) The important part is setting global.player_side_monsters and global.enemy_side_monsters to 2 (that's what controls how many monsters each side is allowed to have at once). The easiest way to inject this would be to copy obj_npc_trainer and cc_battlestart_trainer to new obj_npc_doublebattletrainer/cc_battlestart_doublebattletrainer which are mostly identical but sets these to 2 instead of 1 before the fight starts. (Also note that cc_battlestart_trainer actually can take an array of trainer data, global.encounter_trainer_data has one entry per trainer, so if you want a double battle against specifically two different trainers (instead of an entity like 'twins') you could populate this twice with different monster, dialogue etc data for each trainer.

3) Use an obj_encounterzoneselector, place one in the room and stretch it out over the area you want the battles in and then select the ects_* script with that room's settings (there's two more ects_* scripts with the first town / Driftwood Forest encounter data). They're tied to these markers so you can make things more granular (e.g. have different encounters in different terrain)

Hey yal, i have some trouble when adding another gym leader. Can you help me step by step, i cant figured how to handle badges after winning the battle

Badge status is handled by the array global.player_badges. The first badge is badge 0, the second badge 1 and so on.

You can check cis_leader1 and cis_leader1_beat for an example how this is done:

  • in cis_leader1 there's different dialogue depending on if you have the badge or not (and you only trigger the battle if you don't have the badge). Also it sets up the post-battle script (global.after_battle_event) which is what triggers the cutscene after the battle.
  • in cis_leader1_beat (the script set up to run when you win the battle) you actually get the badge thanks to the line that reads
    csc_enqueue(cc_obtainbadge,0)
    so for a second badge, you'd instead obtain badge 1 in the same way.
(+1)

Hey,

I have been working to get evolution items into the game. I have them working, for the most part. You can select it from the items menu, and then use it on a monster, who will evolve if they have an item based evolution that matches the used item. However, once the evolution ends and the room fades out, the game crashes and I'm not quite sure how to fix it. Here is the crash message:

############################################################################################
ERROR in action number 1
of  Step Event0 for object obj_roomchangefade:
room_goto argument 1 invalid reference to (room) - requested -12341 max is 8
 at gml_Object_obj_roomchangefade_Step_0 (line 7) -                      room_goto(my_room)
############################################################################################
gml_Object_obj_roomchangefade_Step_0 (line 7)

Here is the code of the evolution item:

///itemuse_evolution(amp_id,EvoItem)
function itemuse_evolution(argument0, argument1) {
    var monamp = argument0;
    var monid = global.active_monster_party[argument0,amp_MONID];
    var nevo = NONE;
    for(c = 0; c < global.monster_data[monid,mond_TOTALEVOLUTIONS]; c++)
    {
        if(global.monster_evolution_type[monid,c] == evotype_ITEM)
        {
            show_debug_message("Evolution type equals item")
            if(global.monster_evolution_arg[ monid,c] == argument1)
            {
                nevo = global.monster_evolution_mon[ monid,c]
                inventory_lose_item(my_item,1)
                ds_queue_enqueue(global.pending_evolutions_queue,[monamp,nevo])
                room_goto_fade_dontdestroy(rm_evolution,60)
                break;
            }
        }
    }
    if (nevo == NONE)
    {
        msh_itemuse_show_party_effects("It wouldn't have any effect.")
    }
}


I feel like I must be missing something about the room_goto_fade_dontdestroy function, but I don't know what. Any help would be appreciated. If you need any more details, let me know.

(3 edits)

-12341 is the value of the NONE constant (one of the reasons I picked that number was to make it instantly recognizable). You need to set global.load_room to the current room before changing to the evolution room (and also the global.load_x, load_y and load_direction variables to the player's current x / y / drawdir respectively) otherwise it doesn't know where to put you back - and that's exactly what's happening right now.

(For an example of how to do this, check out player_step_fill which handles the "steps in tall grass to the next random battle" counter, and which sets these before changing to the battle room if an encounter is triggered - side note, this function would also be where you put things like "monsters in daycare gets EXP" and "countdown to eggs hatching" happening)

I tried to edit it can you share a video link to where I can just edit the source code, all of it, I search online can't find a code edit video for game maker

Here's the official GameMaker tutorial series on the code editor. (I recommend using GML Code since Visual doesn't really make things easier, just prettier to look at.)

(+1)

Thank God Oh I needed this so badly, I love the Pokemon engine you made, in fact I truly think it should get more coverage so many people are desprate for one & your is right here. I will definitely watch this

@Yal 🤔 So by “League Master”, is that another way of saying “Gym Leader”?

Since there's only one boss in the demo Fielder might as well be the champion. 😉

[total-mhp-atk-def-mag-res-spd] What does total mean? I get all the others but Idk why total is there

Total is the actual number of stat points, it gets subdivided proportionally over the stats (so the mhp-atk-def-mag-res-spd values are relative - e.g. if ATK is twice as high as DEF, the final stat will also be twice as high, but the actual value that gets stored in the end is TOTAL x ATK/(sum of all 6 stats), not ATK as-is).

The reason for why it's this convoluted is so it's easy to balance monsters - if two monsters has the same stat total, they should theoretically have the same power. (You can see this in Pokémon where there's tiers like "pseudolegendary" (600 stat total), the games never draw attention to this but competitive play communities does and that's where I got the idea originally)

Hello,

With the current logic in a battle with 2v2, if you select to attack 1 monster with both of your monsters and if the first attack kills the selected monster, the attack from the next monster will 'miss' and say 'there is no target'. 

Is there a simple way to update this logic so that if another monster is still alive on the enemy side it attacks that monster instead of missing? Kind of like a 'check for other alive enemies first before missing' function.

Thanks

The part which applies the move is the part (starting at line 671) which begins:

//Apply to all target(s) individually
for(var c = 0; c < array_length(a_targ); c++){

Currently it doesn't do anything special to detect targets not existing, it checks if the number of hits is 0 and the number of misses is also 0 to conclude that there was no target after the fact. (Done immediately after this loop)

So what I'd do is insert a check before this loop, which checks if the original target remains, otherwise gets a random one based on the move (using the function enemies use to pick random targets):

found_targets = 0;
for(var c = 0; c < array_length(a_targ); c++){
     var trg = a_targ[c];
     if(battle_is_alive(trg)){
         found_targets++
     } 
}
if(found_targets == 0){
     a_targ = battle_get_random_targets(a_user, a_comm); 
}
(+1)

Perfect thanks! Works like a charm :D

Hello! 

I was wondering if I could discuss a commission based on this engine? Please email me at squidbatgamesllc@gmail.com if you'd like to discuss this in more detail.

Hello!

I don't really do commissions, I'm afraid - I barely have time to bring my own ideas to life :P But if you're stuck on anything with the engine, leave a question in the comments and I'll reply to it within 24 hours.

(1 edit)

Hi Yal, thank you so much for making this engine, making my childhood dream of making a monster collector game possible! 
Recently I discovered a bug where when interacting with anything that opens a dialogue box (npcs, signs, chests, etc), it instantly reactivates once the dialogue is complete. The only way to 'get out' of an interaction is to hold down an arrow key that turns the player away immediately after the interaction ends.
I am still a beginner at coding, so I'm sorry if this seems like a silly question. I have tried messing around with deactivation alarms and checking the interaction scripts, but nothing worked. 
One thing I did notice is that in the free demo version of the game there's no such issue. Could it be my GMS version? Currently, I am using the newest Version 2024.06.2.162

(3 edits) (+1)

I tried it out and also can see it, so something has changed with GM's processing order that causes this (it was always a bug but it just didn't happen before for some reason, lol - presumably the player was always handled before the dialogue boxes but now it's handled after and thus retriggers the interaction immediately after it closes)

It's easy to fix at least, just update the "Interacting" block of obj_player's step event like so:

//Interacting
if(interaction_cooldown){
     interaction_cooldown--
}
else{
     if(k_a && !p_a){
         var o = collision_circle(
             x + lengthdir_x(TILESIZE,drawdir) - TILESIZE*0.5,
             y + lengthdir_y(TILESIZE,drawdir),
             12,
             parent_interactible,false,true
         )
         if(o > 0 && instance_exists(o)){
             interaction_cooldown = 5
             with(o){
                 if(object_index == obj_npc || object_is_ancestor(object_index,obj_npc)){
                     drawdir = (other.drawdir + 180) mod 360
                 }
                 if(interact_script != NONE){
                     script_execute(interact_script)
                 }
             }
         }
     }
}

Then just initialize interaction_cooldown to 0 in the Create event and everything should work as expected.

Thank you for the solution! 

Hey, I've been looking to create a monster collection game, and this looks like it might be a great base to start with, but I had some questions. I'm planning on using a simplified grid battle format, so battles would take place across a 4x3 grid. Is this something that would be implementable without absolutely tearing the code base apart? There are a fair number of other changes I would be making to the traditional battle system as well, including creatures being able to potentially learn more than four moves, moves that can be powered up, and more, but I think the grid is the biggest change. Is this engine flexible enough to handle those sorts of large system changes, or would I be better off starting from scratch (or with a different engine)? Either way, this seems like a great engine, it's really cool to see something like it created to help others.

(1 edit)

Yeah, all of the grid stuff will need to be custom-made, because there's no concept of positioning and ranges in the engine currently.

What I'm thinking will need to change:

  • obj_battlemonster currently just has its position as a visual thing, it will need to be able to move around... but more importantly they need to keep track of their current grid cell (because that's ultimately what matters, their x/y position is just a representation of that)
    • obj_battlemonstercircle is just a visual object representing the ground currently, but could probably be repurposed into grid squares; you'd give them variables for which grid cell x/y they represent and then be able to use them for reference for where to place monsters + maybe let them keep track of which cells are occupied or not. And then rather than always creating two, you'd create enough for the entire grid.
  • battle_get_valid_targets needs to take positioning and range into account, and in turn move data needs some new stats to store those (which would be added to init_moves/init_move).
    • Additionally, mev_battle_attack and bcontrolstate_ACTIONSELECT_ENEMY should be updated to do nothing if there's no valid moves to use instead of enqueueing the desperation attack (unless there's a target in range)
      • bcontrolstate_ACTIONSELECT_ENEMY additionally will need to select a new "move" action sometimes, e.g. when there's no targets in range. (And presumably you'll need to add a new action to the player action selection menu as well for moving, see bcontrolstate_ACTIONSELECT_PLAYER)
    • mev_battle_attack_select currently creates a menu to select targets when there's multiple targets and a move targets a single target; you could keep this menu but have it also discriminate by range and positioning. If you're OK with it just listing targets that should essentially be the only thing you need to do, but if you want it to highlight the grid cell you're targetting it gets a bit more involved - creating a GGUI region with no background sprite which covers the entire grid, then placing highlight regions so that they line up with individual grid cells. (Check out msh_terminal_load_page's section "Middle main: Box contents" for an example of how to make a grid menu, but the TLDR is that you want one "ggui_menu_region" for each cell, after ggui_menu_preallocate'ing a grid with as many cells as your battle grid). These cells's menu event field would be filled in with NONE if there's no valid target there, mev_battle_attack_select_target if there is.
    • Likewise, you'd do basically the same thing for selecting a cell to move to, except you have NONE if a cell is occupied and a new mev_battle_move_confirm_destination event if it's not + within your move range. (You'd probably want to add sprite elements to each cell which are just a red/green rectangle which represents if it's valid or not)
  • Currently obj_battlemonster remains even if the monster is KO'd and just is invisible, you'd probably want some extra logic to move them out of the grid when they're not replaced with backup so that a dead monster can't impede pathfinding and be selected as a valid target. Just setting their grid cells to a big negative number (like NONE) might be enough, as long as you don't try actually accessing the grid data if the position is NONE.
(+1)

Thanks so much for all the info! Looks like it should be manageable and a good place to get started.

Hey, can I ask what you changed inside of  tsprintf, for  your 2.3x fix please?   I had to import an older version in.  This is what I currently have, thank you: 

///tsprintf(format,...)

function tsprintf() {

//Trivial String Print Format

//Replaces each % percent sign with an argument, then returns the string.

//Inteded to make writing debug printouts less painful.

var c;

for(c = 1;c < argument_count;c++){

    argument[0] = string_replace(argument[0],"%",string(argument[c]));

}

return argument[0];

}

The change was to not modify argument0 directly, but to use a helper variable to hold it (I don't remember what the compilation error was but presumably argument is read-only after 2.3)

The current version looks like this:

///tsprintf(format,...)
function tsprintf() {
     //Trivial String Print Format
     //Replaces each % percent sign with an argument, then returns the string.
     //Inteded to make writing debug printouts less painful.
     var c, s = argument[0];
     for(c = 1;c < argument_count;c++){
         s = string_replace(s,"%",string(argument[c]));
     }
     return s;
}

Thank you very much for the reply, I really appreciate it. Hey what generation of Pokemon would this be like, Gen 2?

There's enough differences that there's not a 1:1 mapping (partially for legal reasons). If I had to narrow it down I'd probably say "gen 3" because there's support for 2v2 battles (and horde battles) which weren't around in the GBC days.

(+1)

Oh that makes sense. Thanks again for making this, it's an awesome engine!

Hey :P just wanted to confirm if it was ok to use this engine in a commercial game or not because I've seen a couple other games that are and I love how this one is set up. I'll be making everything else myself, I just would love the ability to skip the code part of it and get right into the creatives

Of course you can! It's even mentioned in the store page description. The only thing you're not allowed to do is resell it as an asset pack, anything else is fair game, commercial or otherwise.

(And just for the record you are allowed to use all of the sprites/music that comes bundled with the code in a commercial game as well, though since a lot of it are placeholder-ish I can see why you'd wanna replace them :P)

(1 edit)

How do you make it so only the monsters that entered the battle will get exp?

How do you make in battle the move you used next time you are on the same move? So that when next turn can just press x twice in a row to do the same move again?

(+1)

Both of these will need you to track some additional data, I think two global arrays with AMP_PARTYSIZE_ACTIVE slots will be enough: global.party_was_in_battle and global.party_last_move_selected.

  • In obj_battlecontrol's create event, fill these both with 0's in all slots.
  • For only earning EXP in battle:
    • In obj_battlecontrol's step event bcontrolstate_WIN_STEP section, change "if(amp_has_monster(exp_monster)){" to "if(amp_has_monster(exp_monster) && global.party_was_in_battle[exp_monster]){"
    • In obj_battlemonster's step event after the "//Monster's been seen in battle! Add to list." comment, add "if(amp_id < AMP_PARTYSIZE_ACTIVE){global.party_was_in_battle[amp_id] = true;}"
  • For remembering the last move selected:
    • In mev_battle_attack_select, right at the top add "global.party_last_move_selected[obj_battlecontrol.action_monster.amp_id] = menuvalue_x + 2*menuvalue_y"
    • In mev_battle_attack, at the end of the "if(validmoves > 0)" block somewhere, append a switch state like
if(obj_battlecontrol.action_monster.amp_id < AMP_PARTYSIZE_ACTIVE){
switch(global.party_last_move_selected[obj_battlecontrol.action_monster.amp_id]){
  case 0:
    menuvalue_x = 0
    menuvalue_y = 0
  break;
  case 1:
    menuvalue_x = 1
    menuvalue_y = 0
  break
  case 2:
    menuvalue_x = 0
    menuvalue_y = 1
  break
  case 3:
    menuvalue_x = 1
    menuvalue_y = 1
  break
}
}
(1 edit)

Thanks! I got the move to remember which one it uses. I almost got the part with exp. I just it to only give exp to each individual monster based on which one they went against. How do you get for the ID of the opposing monster? So like if it's the first monster they sent out or the second.  

if amp_id == 412 {
for (var i = 0; i < array_length(global.exp_to_grant_in_battle_to_each_monster); ++i) {
if global.party_was_in_battle7[i] == true {
global.exp_to_grant_in_battle_to_each_monster[i] += ceil(exploot);}}}

Code I think will work to check which ones where in the active at the right time:


if opposingMonsterID == 0 {
global.party_was_in_battle1[amp_id]
}
if opposingMonsterID == 1 {
global.party_was_in_battle2[amp_id]
}
if opposingMonsterID == 2 {
global.party_was_in_battle3[amp_id]
}
if opposingMonsterID == 3 {
global.party_was_in_battle4[amp_id]
}
if opposingMonsterID == 4 {
global.party_was_in_battle5[amp_id]
}
if opposingMonsterID == 5 {
global.party_was_in_battle6[amp_id]
}


How would I get the player monster level and the opposing monster level in obj_battlemonster: Step? Something like this? 

global.active_monster_party[amp_id,amp_LEVEL]
global.active_monster_party[0,amp_LEVEL]
(2 edits)

The enemy amp_id's start at AMP_FIRST_ENEMY and then go upwards from there, until they end at AMP_FIRST_ENEMY+PARTYSIZE_MAX_ENEMY.

So the first monster that was sent out is in global.active_monster_party[AMP_FIRST_ENEMY], the second is in global.active_monster_party[AMP_FIRST_ENEMY+c], and so on.

(IDs that don't have a monster in them has an amp_MONID of NONE, otherwise amp_MONID contains the monster ID and amp_LEVEL the level)

(PARTYSIZE_MAX_ENEMY is 12 by default but if you use the constant to figure out how long arrays you need it should work out regardless)

Thanks! I got the exp for only the monster who was in the battle working. 

Bug: When using a item like a potion on the overworld, if you use it on a monster and hold right or left it will scroll the items 30 times a second(You can hear it scroll like crazy). 

How would I make when I use a item on the overworld the screen would stay on the monster select thing instead of closing that and going to the items menu?

The script that applies the selected item is mev_pause_items_use_actually_use, in that you'd want to remove this code at the end which destroys the current menu and the preceding one (the "use/throw away/hold" menu):

instance_destroy(daddy)
instance_destroy()

I don't see the buggy behavior in the engine source file (ggui_menu_handle also has a check that only runs the left/right handler if you've allocated a menu that's 2 at least slots wide so it shouldn't even attempt to move the cursor in the monster menu which is fully vertical) so it might be something you've changed?

(2 edits)

How do you add monsters to your party in the function that gives you lots of stuff to the inventory? Like adding one to the box and stuff?

(1 edit) (+1)

You can find the code for it in the mev_intro_starterselect_confirm script:

var amp = amp_get_new_party_id();
amp_generate_monster(amp,MONSTER_SPECIES,LEVEL)

If you wanna add it to the box instead, use amp_get_new_box_id to get the first free box slot instead of the first free party slot.

(+1)

Two bug reports. In a wild encounter you can mash the x button to make the wild encounter attack before you can do anything. Also when you press the escape button in a wild encounter you can mash the x button to make it press it over and over again only when the first time you escaped.

I'll look into it, probably it can be fixed by manually altering the "active" variable so the menu ignores keypresses during the fadeout.

Hi Yal! Great job with this engine.  Love the battle engine! i had a Q.  How can i equip the Player with all the available Monsters in his party at the start of the game? 

Easiest way would probably be to edit cis_intro_part2 and swap out the cc_intro_startermonsterselect / nickname logic; rather than making a monster choice menu and wait for your input, the startermonsterselect script would instead fill your party with the monsters you want:

var amp = amp_get_new_party_id();
amp_generate_monster(amp,monster_id,level)

First get the ID of the first empty slot in the party, then generate a monster there using its species and level, repeat as many times as you want. There's matching get-first-free-slot functions for the boxes and the temporary enemy slots, too.

To go through every monster like this, rather than hardcoding the monster_id you could loop from 0 to MONSTER_MAX.

Also note that if you really want the player to have every monster in the party, you probably want to increase PARTYSIZE_ACTIVE from 6.

(1 edit)

Amazing!!! i love this engine so much.  Also i tried to add a Monster.  I tried to just input the code in init_monsters but do i need to also add the the "monster_WRAITHMANITA" somewhere else?  What is the best way to add a monster.  if you put this tutorial somewhere let me know thank you for your quick response and everything!

NM I FOUND IT IN CONSTANTS where to put the Macro!

(1 edit)

If you haven't found it yet, try middle-clicking constant / function names to immediately open the script file where they're created. Super useful when navigating a large project. (So in this case, you could've clicked any of the monster_ constants to go to the file where they're defined, and that'd been the place to add new ones)

Also the ctrl-shift-F and ctrl-P hotkeys for opening global search / jump-to-asset can be useful if you know something's name but can't find it.

great short cut thank you!

Also it worked! thank you! one last thing. How i can I code so Player can run away from Trainers? 

The menu event script for this is mev_battle_escape, you'd just need to remove the special case for trainer battles.

Though you might need to take further measures to prevent the player from immediately ending up in a rematch, cc_battlestart_trainer saves the player's position after they've entered the trainer's vision range. So you'd either need to keep track of a previous position somewhere so you can deposit the player out of harm's way, or maybe give the player a temporary invincibility to further battles after they get away (and while this countdown is ongoing obj_npc_trainer's User Event 2 code - which is where they look for players - will ignore them)

Ok thank you I shall attempt this!

what would be the best way to just remove the trainer from forcing me into a battle.  I don't need that functionality in the game i'm building  The player would initiate the battle by walking up and pressing the action button.

(+1)

NM i figured it out!  I think i am good to go for now!!! time to start building!~

Hi Yal! me again.. I've gotten things going and I'm almost there where this works but now I can't seem to figure out how to add a room in the indoors room.  There is no code in the door object and i can't find the script that gives x and y coordinates for the indoors room.  The purely script based engine is very hard to get used to. I'm used to engines with more object based code than scripting.    I also added another tile set for the indoors and the engine crushed it.  Is the room getting resized upon output?

I completely broke the game adding a room.  I deleted it and now player spawns in the middle of the ocean :( Please help.

If you turn on the DEBUG_MODE flag you'll get some helpful printouts in the "Output" window when you load a room (check out the player's Create Event + Alarm 1 event for the code that handles where to spawn).

I think what's happening here is, you saved the game in the now-deleted room, and then when the room doesn't exist anymore the fallback code in mev_title_continue_fileselected which spawns you in the lab might not work anymore if you've changed the layout. (Or if you re-created a room with the same name but a different layout, the saved position will be used but now be in the middle of the ocean)

The door code is in obj_player's collision event with obj_door. But they're meant to be usable without adding any code, instead open the instance in the room editor and check its "variables" window:

Here you select which room to go to and a "label" (whatever text you want), the player is automatically placed at the door object with the same label as the one they entered from. So you can label doors in a town based on which character's house they lead to, and so on. (The code that loads the player based on which door they used is in obj_player's Alarm 1 event)


Not sure why the tileset is so distorted but my theory is that it might've gotten broken if it's got a different size from the existing ones? (320 x 256). Height shouldn't matter but the 320 pixel width is since the tile indices are used for collision checking (left 160px (= 10 tiles) are walkable tiles, right 160px are walls).

Also make sure the tileset settings are correct!

These should also match the grid size of the tile layer you're placing these on (A), re-selecting which tileset to use on the layer (B) will refresh how the tile layer is drawn as well.


Thank you. I figured out your label system early on.  I tried to make a room in the indoor and made a door and added a new label.  The player would touch the door in overworld and respawn back in the overworld.  I didn't know what to do. the  next thing i did was use the label of one of the already existing locations in "indoors" and altered the labels of one of the other pre existing indoors.  this caused a strange confusion to occur and the tiles were crushed.  I then decided perhaps it would be best to make a new room.  I copied the room to ensire if there were any game code it would remain intact but upon doing so i destroyed the game.  I deleted the room and then repawned in the ocean.    I just checked the settings on the tiles and they are correct and also correct in the room.  As you are correct the code must be sending me to the ocean of a room that doens't exist however, it has the same sound as the forrest so i think that's where its sending me.  How can i fix?  I may also try adding the tiles in want to the pre existing tile set provided to see if that works.

i just checked the create event and alarm 1 of the player. I have no idea how to fix.  

What I was thinking was, you'd enable DEBUG_MODE (line 5 of init_constants is "#macro DEBUG_MODE false", change it to "#macro DEBUG_MODE true") and then you'll get messages telling you what happens. E.g. if a door transition takes priority, the game will print "Came through a door, jump to LABEL" (so if you're not where you think you are, you can check that the label is correct) and it'll tell you "Player loaded! (room=NAME OF ROOM)" as well so you can tell where you ended up.

You could try adding additional show_debug_message's to e.g. print the player's position after loading, that should make it easier to find in the room editor:

show_debug_message(tsprintf("Player location: %, %",x,y))


As I said before, going through a door will place you at the door with the same name in the other room. So a drawback of this approach is that you can't link two doors in the same room together (because when looping over the door objects it'll find whichever of the two doors with that label is first in the instance list and always pick that). If you want to warp between places in the same room I'd probably create two new objects, "obj_teleport_entrance" and "obj_teleport_exit", which has a label the same way the doors have. Then in player's collision with teleport_entrance, run this code:

var target_label = other.label;
with(obj_teleport_exit){
  if(label == target_label){
     other.x = x;
     other.y = y;
     break;
  }
}

Now each teleport pair would use one entrance and one exit. If you want a teleport to be in both directions you'd have entrance A and exit B on one side and entrance B and exit A on the other side; make sure to place the exit some distance away from the entrance (otherwise the player gets stuck in an infinite loop of warping between them).

Are you going to continue working on this soon?

I consider it complete (unless there's a game-breaking bug).

Hi Yal, hope you had a great Summer. I've been trying to setup a 'shop' that displays the monsters seen, and purchase/craft monsters from a list that of them you've caught. 

I've taken your UI of mev_pause_moncyclopedia for the shop layout, and am attempting to use the item purchasing goodness from  msh_spawn_shop_list and its menu event accomplish this. 

The thing I think I'm currently stuck on is using the proper code  to set up the var it which I want to be the specific ID of the monster you're hovering over .Then carrying over that info with shop_item variable to the shop menu event. 

I've been using it  =  global.monsters_seen[d] but after starting to use the debug feature, I realized this is not giving me what I need lol.

 Here's the code block I'm struggling with to accomplish that. Its the block for the mon's you've caught and thus should be purchasable.  I'll link the full script code in a comment below if that helps. Thanks!!!

//Add meta data as well, based on how much info the player has about the monster.

var d, mev, it;

draw_set_font(font_n)//Needed by string_wrap

for(d = 0; d <= maxmon; d++){

vev= d

yy = lerp(0.05,0.95,d/cmax)

hh = lerp(0.05,0.95,(d+1)/cmax) - yy

// ggui_menu_region(0,vev,mev,0.05,yy,0.95,yy+hh)

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

if(global.monsters_caught[d]){ 

//Wrap flavor text so it fits the box we add below

mev = argument0

it  =  global.monsters_seen[d]     //global.monsters_caught[d]

ggui_fill_meta(0,d,global.monster_data[d,mond_SPRITE_BATTLE],0,global.monster_data[d,mond_NAME],string_wrap(global.monster_data[d,mond_CRAFT_SLOT_SOUL_STRING],VIEW_W*0.6*0.8))

var soul = global.monster_data[d,mond_CRAFT_SLOT_SOUL] 

shop_item  = it

shop_cost  = soul

    

}

function msh_botsmith_spawn_monsterpurchse_list(argument0) {

//mev_pause_moncyclopedia()

//Make sure statistics are up-to-date

msh_recompute_seencaught()

//Find max monster

var maxmon = 0, c;

for(c = MONSTER_MAX-1; c >= 0; c--){

if(global.monsters_seen[c]){

maxmon = c // maxmon is arraylength

break

}

}

    show_debug_message(global.monster_data)

with(instance_create_depth(x,y,depth - 1,obj_gguimenu)){

ggui_menu_preallocate(1,maxmon +1)

//Left pane: monster list (scrollable)

ggui_frame(0,0,VIEW_W*0.4,VIEW_H,spr_messagebox)

ggui_frame_set_scrolling(false,true,1,10,false,true)

var cmax = 10, yy, hh, vev;

ggui_element_text_settings(font_mainmsg,c_white,0,1)

for(c = 0;c < cmax;c++){

vev= c

yy = lerp(0.05,0.95,c/cmax)

hh = lerp(0.05,0.95,(c+1)/cmax) - yy

ggui_element_text_scrollable(0.1,yy+hh*0.5,0,vev)

}

//Add meta data as well, based on how much info the player has about the monster.

var d, mev, it;

draw_set_font(font_n)//Needed by string_wrap

for(d = 0; d <= maxmon; d++){

vev= d

yy = lerp(0.05,0.95,d/cmax)

hh = lerp(0.05,0.95,(d+1)/cmax) - yy

// ggui_menu_region(0,vev,mev,0.05,yy,0.95,yy+hh)

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

if(global.monsters_caught[d]){ 

//Wrap flavor text so it fits the box we add below

mev = argument0

it  =  global.monsters_seen[d]     //global.monsters_caught[d]

ggui_fill_meta(0,d,global.monster_data[d,mond_SPRITE_BATTLE],0,global.monster_data[d,mond_NAME],string_wrap(global.monster_data[d,mond_CRAFT_SLOT_SOUL_STRING],VIEW_W*0.6*0.8))

var soul = global.monster_data[d,mond_CRAFT_SLOT_SOUL] 

shop_item  = it

shop_cost  = soul

    

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

else if(global.monsters_seen[d]){

mev = NONE

ggui_fill_meta(0,d,global.monster_data[d,mond_SPRITE_BATTLE],0,global.monster_data[d,mond_NAME],"???")

shop_item[d] = NONE

shop_cost[d] = 0

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

else{

mev = NONE

ggui_fill_meta(0,d,spr_unknownmonster,0,"???","???")

shop_item[d] = NONE

shop_cost[d] = 0

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

ggui_menu_region(0,vev,mev,0.05,yy,0.95,yy+hh)

}

//Upper right pane: monster sprite + name

ggui_frame(VIEW_W*0.4,0,VIEW_W*0.6,VIEW_H*0.5,spr_messagebox)

ggui_element_sprite_current(0.5,0.8)

ggui_element_text_settings(font_mainmsg,c_white,1,0)

ggui_element_text_current(0.5,0.8)

//Lower right pane: flavor text

ggui_frame(VIEW_W*0.4,VIEW_H*0.5,VIEW_W*0.6,VIEW_H*0.4,spr_messagebox)

ggui_element_text_settings(font_n,c_white,0,0)

ggui_element_desc_current(0.1,0.1)

//Lowest right pane: total statistics

ggui_frame(VIEW_W*0.4,VIEW_H*0.9,VIEW_W*0.6,VIEW_H*0.1,spr_messagebox)

ggui_element_text_settings(font_nfat,c_white,1,1)

ggui_element_text(0.5,0.5,tsprintf("Species Witnessed: %          Species Possessed: %",global.monsters_seen_total,global.monsters_caught_total))

ggui_element_text(0.5,0.8,tsprintf("Required Parts: %",global.monster_data[d,mond_CRAFT_SLOT_SOUL_STRING]))

}

}

global.monsters_caught and global.monsters_seen are arrays of booleans, which means each slot is true if you have caught/seen that monster and false otherwise. In this case you'd just want to carry over the counter itself, since it's the monster ID - so menuvalue_y for the currently hovered item (since it's a vertical menu).

Also, in the moncyclopedia when setting up the events (ggui_menu_region statement) you'll see we give every line a NONE event (which means nothing happens if you press the "accept" button with it highlighted), for your case you'd maybe want to make this conditional - if the monster is available for purchase (global.monsters_caught[d] is true) you'll set up a shop event (which e.g. checks if you can afford the monster and if so proceeds, carrying over the current menu's menuvalue_y as the monster ID the next-level menu refers to), if it's not available (e.g. you haven't caught it yet) you create a NONE event instead.

Thanks Yal! That explains why the monster that keeps getting purchased is Charchne, who is ID no. 1 haha. Could you expand on how I can use these boolean arrays to carry over a counter to properly match the currently hovered mon?  

(1 edit)

To pass over a value, in the mev_ script you'd do something like this:

with(instance_create_depth(x,y,depth-1,obj_gguimenu)){
     daddy       = other.id
     my_monster  = other.menuvalue_y
     //Create frames, elements and events like normal
}

(Similar to the scripts for doing stuff to party monsters, but instead of referring to the AMP we refer to a raw monster ID)

Hi Yal

 Could you help me in the game gun 10 summer, because I have trouble finding a weapon to break the green and blue blocks.  I'm currently in Western Flat, after entering the room downstairs where I'm talking to someone there, I can't go back upstairs because the shotgun isn't enough.  When, after the fight, the firewall "A" opens, which I go through, and after entering the room, the computer asks for an ID that I don't have and I don't know where to get it.  In this room, my shotgun is also not enough to get to the top

 What should I do, what am I doing wrong

 I am asking you for help

Hi Yal

 Could you help me in the game gun 10 summer, because I have trouble finding a weapon to break the green and blue blocks.  I'm currently in Western Flat, after entering the room downstairs where I'm talking to someone there, I can't go back upstairs because the shotgun isn't enough.  When, after the fight, the firewall "A" opens, which I go through, and after entering the room, the computer asks for an ID that I don't have and I don't know where to get it.  In this room, my shotgun is also not enough to get to the top

 What should I do, what am I doing wrong

 I am asking you for help

Hello again Yal! Do you know if this engine works OK with the most current versions of GM that have come out? I mainly ask because I know there are some retired functions (like arraysize 1D) used. I haven't updated it in forever just in case haha

also a general GM question i'm trying to figure out, I've noticed you use var c for most of you "for" loops. Does that 'c' value get carried over and iterated on in scripts that use multiple 'fors' or is the 'c' reset upon a new 'for'? 


Thanks! ^.^

I tested most of my engines with 2023.8 to make sure nothing had broken, I only found a single issue (a missing sprite_exists check in the open world 3D engine). array_length_1d is deprecated but trivial to replace (array_length does the exact same thing) so I figured there's no rush, there's currently no easy way to find a list of all deprecated functions in use in a project so I'd probably just miss something, think the project is safe and then run into a massive tech support nightmare when a new GM update drops anyway.

As for the for loop variable name, I'm just using "c" because there's a programming language called "C++" so writing "c++" as the increment operation is funny. That's the whole reason :P

Anything declared with "var" only exists in the piece of code it belongs to, so c's in different scripts will not affect each other. And with multiple loops in the same script, you reset the variable to 0 at the start of the for loop, so it doesn't matter it's reused. (The exception being when you have a loop inside a loop  - then you need separate variables so the inner loop won't mess with the outer loop).

Hey Yal, I picked the engine up a couple days ago and I love it, I have 2 questions and I was wondering if I could get some help or advice.

1. I've redone the move points system to be a pool of points that each move pulls from. I was wondering is there anyway to check to see which side used the attack so the enemy doesn't use the pool of points as well?

2. How does the enemy attack selection work? It looks like it puts all the attacks into a list and then shuffles them around and picks the first one. I was wanting to change it so it's choices are weighted based on mp cost/turn count, so higher mp moves are selected as the fight goes on.

Thanks Yal

(1 edit)

1: There's a 'user' field for enqueued actions, for instance the a_user variable in the ctst_TURNQUEUE state in obj_battlecontrol's step event. (this state is probably when you want to consume the points, since it's when the action actually happens). This "user" field is a battlemonster object ID so simply check its side variable: if it's equal to side_ENEMY it's an enemy and shouldn't consume points.

2: Correct, enemies just pick a random move this way (add all valid actions to a list, shuffle it, pick the first option). If you want something priority-based you could rework what happens in the bcontrolstate_ACTIONSELECT_ENEMY segment to use a priority queue instead (ds_priority functions), where you insert things and they're automatically sorted so you can pick the highest priority value - it's pretty much analoguous to how ds_lists work and the only hard part is figuring out how to compute the priorities - you might want to add some new fields to the move database for storing base priority and priority increase per turn to make this easier to control on a case-by-case basis, and maybe rework target selection a bit to account for type matchups (i.e., add every possible move-target combination to the list but multiply the regular priority with the type multiplier for that target)

(Also you might want to still add a little bit of randomness to the priorities, so the AI doesn't become completely predictable and the player can exploit it)

(1 edit)

I've also found a bug whereby the game will crash if you try to catch a monster that has already been captured in the same turn, because there is no longer a target. So two player party members, on both party members turn you use a monster ball item, if on the first party members turn the monster is caught, the second party members turn tries to use the monster ball but they can't be captured again, causing a crash. I fixed this by checking in the battle_control before using an item, if the item is a catching item type if the target is still 'alive', and if not, tell the player that it failed etc. If you can replicate might be worth fixing for everyone etc

Oh yeah, might need to have a look into that. I know even the released version of Pokémon Colosseum had a bug which let you duplicate items if you used an item as the first party member and then reordered items on the second party member's turn (so you could get infinite Master Balls that way) so it seems this kind of stuff is tricky to get right.

Hello, another question, how would I go about making it so that the 'box' management makes it so you have to keep two monsters in your party instead of just one? I'm focusing exclusively on double battles and don't want the player to have only one monster in their party at any point

You'll need to change the mev_terminal_grab script a bit. This line

if(amp_read_var(AMP_FIRST_ACTIVE,amp_MONID) == NONE){

should be changed to

if(amp_read_var(AMP_FIRST_ACTIVE,amp_MONID) == NONE || amp_read_var(AMP_FIRST_ACTIVE + 1,amp_MONID) == NONE){

and now emptying either of the first two slots in the party (by going below 2 party members) should cancel the operation.

(Also, you probably want to update the message that is printed when this happens to read "2 monsters" instead of "1 monster", a little further down in the script)

(1 edit)

I just realized, doing it this way still will cause some issues since grabbing a party monster will move any monsters after it in the party lineup forwards one slot, and the undo overwrites the original slot (so grabbing the first monster when you have only 2 in the party will move the 2nd monster to the 1st slot, then it's overwritten by the undo).

It's probably safer to move the party-amount check to just after line 18 (inside the second "if(menuvalue_x < columns_party){" block), and have the check be something more like this:

var partymons = 0;
for(c = 0; c < PARTYSIZE_ACTIVE; c++){
  if(amp_read_var(AMP_FIRST_ACTIVE + c,amp_MONID) != NONE){
     partymons++;
  }
}
if(partymons <= 2){
  //Error message code goes here (but without the undo, since we don't always pick up the monster now)
}
else{
  //Regular "pick monster up" code goes here
}

So basically, disallow even picking up the monster if you don't have at least 2 after the operation.

(1 edit)

Thank you. If I'm understanding correctly, this will also mean that the player can no longer 'swap' a monster in the party for one in the box if they have only 2 in the party meaning they will first have to get the monster they want from the box and add it as the 3rd party member, then put the one from the party into the box they don't want, correct?

I actually went about this a different way in the end. I modified the obj_terminalmenu step event so that you can't cancel out of the menu if the party has less than two members and put a warning if so. I remove the 1 party member warning from the grab so that you can freely move monsters however the player wants. I can't think of a reason why this wouldn't work, can you?

This sounds like it should work as well, it doesn't matter if you enter an invalid state as long as you're forced to revert to a valid state before you can close the menu. Just be careful about implementing autosaving, new ways to cancel the menus (etc) so the player can't end up stuck with too few monsters that way.

(1 edit) (+1)

Yes for sure, I realised as well that there is not a release function in the box menu, at least, not one I can see??? So if that's the case and I implement one, I'll just need make sure that the party + box monsters is greater than 2 before you release a monster 😌. But anyway, big thanks for your help and the engine, has been a little tricky to get my head around some things but its progressing nicely

Hello again Yal! Hope you're having a good summer,

I've been working on a shield system by copying how HP works and changing all the variables to ShieldHP essentially. I'm having trouble figuring out how to get the damage to "jump" over to reducing normal HP after the shield bar has been destroyed. ( I have separate dmgapply scripts for shield dmg and normal dmg below) It seems like the damage is stuck on trying to take from the sheildHP pool even after it has reached zero. Probably some simple thing i've overlooked :) Here's what I'm working with: 


//Damage

if(pow > 0){

        var dmgdata = compute_damage(a_user,trg,a_comm);

if(sheildcheck >0){

n = instance_create_depth(trg.x,trg.y,depth,obj_dmgapplyshld)

n.my_dmg = ceil(dmgdata[0]*ail_power_multiplier)

n.my_mul = dmgdata[1]

n.my_eff = dmgdata[2]

n.my_mon = trg

n.my_user = a_user

n.my_move = a_comm

n.this_is_an_attack = true

}

//********************

if(sheildcheck < 1){

n = instance_create_depth(trg.x,trg.y,depth,obj_damageapply)

n.my_dmg = ceil(dmgdata[0]*ail_power_multiplier)

n.my_mul = dmgdata[1]

n.my_eff = dmgdata[2]

n.my_mon = trg

n.my_user = a_user

n.my_move = a_comm

n.this_is_an_attack = true

//User might hold an item that improves attack effectiveness

if(battle_item_might_affect_this(a_user.amp_id,itemvalidflag_AUTO_ATTACKING)){

var it = amp_read_var(a_user.amp_id,amp_HELDITEM)

n.my_mul *= script_execute(global.item_data[it,id_USESCRIPT],[a_user.amp_id,trg.amp_id,a_comm],global.item_data[it,id_USEARG])

}

}

}


Thanks!!

The code you posted seems to make sense. The interesting thing here is how you compute sheildcheck, and you didn't include that bit of code...

Also, just to get the obvious out of the way: obj_damageapply still does HP damage and not shield damage, right? (So you didn't accidentally change that one as well when you changed all the variables)

(Also note that your two sheildcheck checks are >0 and <1 so both of them will occur for values between zero and one! Is this intentional?)

trg here is the target monster object and we've already checked that it's alive, so you really only need to check if amp_read_var(trg.amp_id,amp_SHIELDHP) is greater than zero: if so, deal shield damage, else deal regular damage.

Hello again,

I'm trying to make it so that when the cursor is over a move in battle, where the box that shows the type of the move and it's MP, I can add in a sprite to indicate the type. I'm looking in the attached image but I'm not sure what element to use to get it to draw the correct icon (I already have the move data setup with the type icons, I just need to know how to draw it)


gguielt_CURRSPRITE element type (added with ggui_element_sprite_current script) is the icon sprite of the currently hovered item in the menu, this is what you want to use here.

Since the data is filled into the menu using ggui_menu_add_option_text it fills the sprite data with NONE, but you could copy ggui_menu_add_option_text and create a new script ggui_menu_add_option_text_and_sprite that also fills the sprite/image data (the two arguments to ggui_fill_meta that are set to NONE within ggui_menu_add_option_text) using two new arguments at the end, and then use that instead in mev_battle_attack. (There's already the _icontext and _gridimage helper scripts that fills the sprite data, but they also set up the elements so that the image is used directly there in the body of the menu, which isn't what you want for this - we want this new script that fills the icon data but doesn't use it yet)

Ah I see thanks, I'll give that a try

Viewing most recent comments 1 to 40 of 107 · Next page · Last page