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) {
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.
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.
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.
-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.)
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
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)
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.
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);
}
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.
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.
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
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:
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.
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.
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.
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;
}
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.
← Return to asset pack
Comments
Log in with itch.io to leave a comment.
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:
csc_enqueue(cc_obtainbadge,0)
so for a second badge, you'd instead obtain badge 1 in the same way.
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:
Here is the code of the evolution item:
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.
-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.)
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:
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):
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.
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
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:
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.
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:
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:
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.
Oh that makes sense. Thanks again for making this, it's an awesome engine!