A downloadable asset pack for Windows

Buy Now$14.99 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.8 out of 5 stars
(13 total ratings)
AuthorYal

Purchase

Buy Now$14.99 USD or more

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

Source Code (GMS 2.3) (fixed, v.2) 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 74 · Next page · Last page

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)

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

Hello again Yal, happy July :) Here's some things I've been having trouble understanding lately: 

How to use properly reference a AMP (friend and foe) within obj_battlecontrol. I'm working on shield system, (where mons have to break through a shield before being able to attack the enemies HP) 

I'm trying to do a check on a new stat (shieldHP) and if the AMP's shieldHP stat is >1, a visual shield object will appear in front of a mon after it's summoned.

 My problem is  simply trying to understand how you have been using the amp.id variable in obj_battlecontrol do to similar stat checks. I've tried a few things and placing the code in a few spots. I don't think I quite get what variable to place in front of it (with the period separating amp_id. 

Here's the current code I'm trying in bcontrolstate_ACTIONSELECT_STEP 1 (around line 320)

var getshld = monster_get_maxshld_hp(action_monster.amp_id);

if(getshld > 1) {

instance_create_depth(cx,cy,d_player + -100,obj_battlemonster_sheild)} 

the error messages basically keep saying the xyz.amp_id variable is undefined. Any help understanding this is greatly appreciated as always :)

I think you're going about this the wrong way - if you want a visual effect on a per-monster basis it might be easier to have obj_battlemonster handle it? It's already aware of which AMP data block it owns so it's a bit easier than going through the control (who manages a ton of monsters at once) Plus, with your current approach you'll create a new shield effect object every turn - if you don't remove them afterwards you'll end up with dozens or hundreds of them in every battle...

In the draw event, add some new code like this:

if(state == bmonsterstate_NORMAL){ //Monster is guaranteed to be alive and valid in this state
  if(global.active_monster_party[amp_id,amp_SHIELDHP] > 0){
     draw_sprite_ext(spr_shield,0,x+dx,y+dy,image_xscale*drawscale,image_yscale,image_angle,image_blend,image_alpha)
  }
}

There's ways to refine it, like adding effects whenever the shield status changes (broken / regenerated) by keeping track of the status the previous step and doing stuff when it's different from the current step. But the important part for now is making it draw properly.

Hi Yal, any idea why I'm getting errors in global.active_monster_party? I've been so tied up in working on totems and menus, when I went back to look at battles, this happened :( Something to do with the Macro NONE i'm sure, but I cant figure out what. 

ERROR in

action number 1

of  Step Event0

for object obj_battlecontrol:

Push :: Execution Error - Variable Index [-12341] out of range [419] - -5.active_monster_party(100075,-12341)

at gml_Object_obj_battlecontrol_Step_0 (line 110) -                             var montype = global.active_monster_party[n.amp_id,amp_MONID];

#########################################################gml_Object_obj_battlecontrol_Step_0 (line 110)


If I comment out the block starting from line 110, then I just get the same message in the obj_monster HUD 

Push :: Execution Error - Variable Index [-12341] out of range [419] - -5.active_monster_party(100075,-12341)

 at gml_Script_amp_read_var (line 3) - return global.active_monster_party[argument0,argument1];

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

gml_Script_amp_read_var (line 3)

gml_Script_monster_get_name (line 4) - var s = amp_read_var(amp_id,amp_NICKNAME);

gml_Object_obj_battlemonsterhud_Draw_0 (line 12) - draw_text(xx,yy,monster_get_name(amp))

Thanks so much!

Interestingly, the problem does not occur if the battle is a hoard battle... Hmm.. There must be something I need to fix with 1 v 1 battles I think

(2 edits)

The thing that's happening here is that you try to read the data of a monster that has a NONE AMP reference. It's specifically being done in the block that creates the enemy battlemonster objects.

From what I can see, the issue happens when you start a horde battle without generating enough monsters to fill all enemy horde slots. (This is why it works in 1v1 battles - you always generate 1 enemy monster so creating 1 battlemonster will avoid reading outside the available data)

Should be simple to solve, at least. Wrap this block


in a copy of this condition


and it shouldn't try to read the unset data anymore. (Note how the inner block also changes the monster state from "DEAD" to "NORMAL" when doing this, which will also lead to issues down the line even if you ignore the data reading bit - this is what causes the second crash)

Actually, the reverse is working (horde battles working, 1v1 battles are not) but I tried adding that condition but then got a similar error to what I have been  getting: 

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

ERROR in

action number 1

of Draw Event

for object obj_battlemonsterhud:

Push :: Execution Error - Variable Index [-12341] out of range [419] - -5.active_monster_party(100075,-12341)

 at gml_Script_amp_read_var (line 3) -        return global.active_monster_party[argument0,argument1];

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

gml_Script_amp_read_var (line 3)

gml_Script_monster_get_name (line 4) -        var s = amp_read_var(amp_id,amp_NICKNAME);

gml_Object_obj_battlemonsterhud_Draw_0 (line 12) -               draw_text(xx,yy,monster_get_name(amp))

sorry for the trouble! I really appreciate your help as I am still trying to make sense of the ins and outs of the battle system

(1 edit)

Either way it's still caused by there being NONE monster IDs in the list of enemies to fight. Weird.

I had a little dig in the codebase and I think I have another idea for what could cause this. The code that checks for valid monsters to send out only checks if HP > 0. If the matching AMP ID's amp_MONID is NONE then we have an invalid monster ID and reading data from that will cause issues.

Do you set up / clear data for totems properly (similar to how the engine handles enemy data in random encounters)? It feels like there might be something going on with partially initialized data that causes this.

One idea might be to extend battle_get_valid_reinforcements a bit so that line 6 checks this condition instead:

if(global.active_monster_party[mon,amp_HP] > 0 && global.active_monster_party[mon,amp_MONID] != NONE){

It's not fixing the core issue that causes the invalid data but it at least stops trying to spawn a nonexistant monster. Maybe it'll be enough, since most other AMP manipulation scripts checks if the monster ID is NONE to check if a slot is valid.

Hello again Yal! This time i'm back with more general questions that I can't seem to figure out yet. 

I'm using the framework of msh_spawn_inventory and how it conveniently lets players tab through multiple pages. The way i'm trying to use it, I need certain items to be different font colors but I cant seem to figure out how as this  uses ggui_fill_arbtext. any advice appreciated :) 

Also, could you give tips on how we might be able to display animated sprites within the menus/cutscenes. They all seem static from what I can tell. 


Thanks so much as usual! 

Let's start with the easy bit, animated sprites. Just create a GGUI sprite element with the subimage set to -1, and it should work (draw_sprite uses the current animation subimage of the object if you draw a sprite with subimage -1, and sprite elements are drawn with draw_sprite passing through all parameters as-is). Potentially you might need to give the menu object an animated sprite as well (by assigning sprite_index) but I think it'll work even without it.


Now for "certain items with a different color": It's a bit unclear what you mean by "items" here? Items in the inventory or GGUI elements?

The idea with (Scrollable) Arbitrary Text elements is that you have a text field that reads data from the currently highlighted menu item rather than being a preset text (they're "arbitrary" as opposed to the Description field which originally was the only per-element-changeable text, and hardcoded text strings - I added the arbitrary text fields because I realized sometimes you need more than one per-element text field).

So basically, the element itself has no text, just a reference to the Arbitrary Text Array for that menu. But the Arbitrary Text Element owns the formatting (font, color, alignment) so by default, it can't change depending on what's highlighted - you'll need to make a new type of element which accesses an array of both text and formatting information (studying how gguielt_ARBTEXT works internally and copying the behavior for a new gguielt_ARBTEXTWITHFORMATTING might help here - you'd use an array similar to menu_arbtxt but rather than just storing text, you'd store a tuple [text, font, color, halign, valign]).

But if you just want different fields to be different colors (e.g. HP is red, money is yellow) it's very simple, use ggui_element_text_settings to change formatting parameters (all further text elements are created using these settings until you change them again).

Thanks Yal :D The frames do animate at -1, but it seems to animate very fast. (maybe 60 fps fast? lol) any thing we can do to set the speed? 

(+1)

Hmm, I guess this is a side effect of the menu not having a sprite, so it doesn't use the sprite's animation speed... welp, it's easy to fix at least.

Set image_speed to a value lesser than 1 from the menu object's perspective (i.e. inside the block that starts with the "with(instance_create_depth(...obj_gguimenu)" call).

I find values between 0.1 and 0.2 work the best for legacy sprites that default to 60 fps, so start off with 0.15 and adjust as needed until you're happy with the result?

Hi Yal! Hope you've been well. Any ideas on the best way to implement a "totem" system? 

Basically, certain moves create totems - essentially a temporary, targetable object that gives buffs, etc until they are destroyed. 

I thought the best way would be to add them to the Dex .Then have them sent out, then destroy the instance when they reach 0 HP or at the end of battle.  

I'm not sure how to approach adding a temporary mons to the battlefield (also considering the opposing team could use this move!)   I'm thinking the move would have to temporarily increase the max team size to work. 


Any thoughts are appreciated :)

(4 edits)

Good job sticking with the project for 6 months! I'm used to people giving up much sooner but seems you're one of those rare determined people that actually finishes their games ^__^

Your analysis is pretty much correct!

Adding temporary mons would be pretty easy, as you can see in obj_battlecontrol's step event ctst_ACTIONSELECT block, it loops over all existing monster objects when building the list of who gets to act, so just creating instances should work. You should add a new "is_totem" variable to the battlemonster object so that totems are treated differently, though (it's always false, but when creating a new instance for a totem, you'll set it to true after creating it).

You might wanna do some changes in obj_battlemonster's bmonsterstate_DIE  to change the KO messages for totems (and delete the object if dead - an empty slot currently still is a monster object!) so they're not around when the ctst_REINFORCEMENTS step happens, or that team will be able to send in additional monsters to take the place of any destroyed totems, turning it into a permanent team size upgrade for that battle.

You will also need to change this block:

default:
    //Most ailments don't bypass action input, so let's go do that.
    if(next.side == side_PLAYER){
        substate = bcontrolstate_ACTIONSELECT_PLAYER
    }
    else{
        substate = bcontrolstate_ACTIONSELECT_ENEMY
    }
break

Totems should always go to bcontrolstate_ACTIONSELECT_ENEMY (automatically select), regardless of if they're player or enemy. (Unless you want players to be able to control what their totems do, of course - I'm just interpreting your description as totems being kinda passive/automatic)

Their buffs could be implemented as new moves with the appropriate target range set up (e.g. movetarg_ALLALLY to buff all allies), then you have the new totem species learn the buff-moves it should provide at level NONE (i.e., always knows them).

Since all monster stats are read from the AMP and the battlemonster objects just have a pointer to that (rather than having their own stat variables), I'd say you could put totem data in the "enemy" section of the AMP (since that's temporary data which gets cleared after a battle) - just run amp_get_new_enemy_id / amp_generate_monster using the totem species for this. You just need to manually free up slots again (with amp_clear_monster) when a totem is destroyed so you don't run out of slots entirely if a long battle has many totems created and destroyed.

Thanks so much Yal! I am still familiarizing myself with the engine, but as i've taken your above advice into action, I realize I may be in over my head with a this rather complicated totem mechanic and may need to revisit it later. BUT if you have time, these are a few things I'm running into: 

- Not sure where in the init moves to put amp_generate_monster(1,monster_totem_1,1) 

I've tried placing it in a few of the argument fields there with no success. Maybe I need to create a "status"  with 100% acc and code it to create totems that way? 

- I have tested forcing a mon to appear in battle by just doing a press key event in obj_battle_control. I can't get it to pop in a duo battle (with one mon on my team) but it will pop into my party (and can be swapped into lol) I wonder if creating a designated slot for totems might be the way to go, unless I'm missing something which is likely lol. 


Thanks a bunch as usual!! 

The easiest way to do really weird things that doesn't fit into the standard move data would be to hijack the "aniobject" argument (mvd_ANIMATIONOBJECT slot of move data). It's intended to be used just for visual effect controllers, but nothing's stopping you from creating an object which in turn sets up a totem, or does other weird stuff (a boss could have a move that plays a cutscene, for instance). The only thing to keep in mind is that it needs to be a child of parent_battleeffect if you want the battle to pause until the object is destroyed (i.e. it's gonna be around for more than one frame). Do the behavior you want to achieve in the step event, since we set some variables after creating it (and thus they're not accessible in the create event).

Also the code you're running is probably not doing what you think you're doing...

The function is amp_generate_monster(slot,species,level). First argument is slot, if you just put an "1" there it's always going to overwrite whatever's in the second party slot (array numbering starts at 0 in Game Maker). You want to ask the engine for an unoccupied slot, so you probably want

var slot = amp_get_new_enemy_id();
amp_generate_monster(slot, monster_totem_1, 1)
var totem = instance_create_depth(xx,yy,dd,obj_battlemonster)
totem.amp_id = slot
totem.name = monster_get_name(totem.amp_id)
totem.sprite_index = monster_get_battlesprite(totem.amp_id)

xx, yy and dd are the X, Y and depth values to create the totem on, you'd have to compute them somehow. For this you could use the fact that effect object you created has a variable "user" set by the battle controller, which is the ID of whoever ran this move, so if you e.g. want the totem to spawn in front of the user, you'd do something like:

var xx, yy, dd;
xx = user.x + user.sprite_width*0.5
yy = user.y + 10
dd = user.depth + (user.side == side_ENEMY)? -10 : 10;

(potentially you might also wanna use the "target" variable which is the move's target, e.g. if you could create a totem that affects someone else in a multibattle)

Hi Yal thanks for everything :) Its a great engine. I was wondering what I could do to implement mouse controls? When I hover my mouse over the game window, the cursor disappears. Thanks again

(2 edits)

Let's start with the easy part, how to enable the mouse cursor. Open the Game Options, then Windows, then the Graphics tab and check this box:


(if you want to draw your own cursor you could draw a sprite at the built-in variables mouse_x, mouse_y - each of the control objects could do this)

Having actual mouse control is considerably more complicated but I think something like this would be the easiest way:

  • Edit ggui_menu_handle to comment out all the keyboard controls
  • Add a new loop that goes through all frames and does something like this:
if(active){
for(c = 0; c < ggui_frames;c++){
  if(mouse_x > ggui_frame_l[c] && mouse_x < ggui_frame_l[c] + ggui_frame_w[ c]){
  if(mouse_y > ggui_frame_t[c] && mouse_x < ggui_frame_t[c] + ggui_frame_h[ c]){
     //We're in this frame, select it
     for(var d = 0; d < menu_w; d++){
     for(var e = 0; e < menu_h; e++){
         if(menu_frame[d,e] == c){
             menuvalue_x = d; menuvalue_y = e;
             if(mouse_check_button_pressed(mb_left)){
               //Clicked something! Run the regular "A button" code
               if(menu_event[menuvalue_x,menuvalue_y] != NONE){
                   sfx(snd_menu_ok)
                   script_execute(menu_event[menuvalue_x,menuvalue_y])
               }
               else{
                   sfx(snd_menu_buzzer)
               }
             }
             break; //End when we find the first frame that matches
         }
     }
     }
  }
  }
}
}

Now this will remove the "cancel button" option you had before but you could solve that by adding a "X" button in the top right corner. (You still need to preallocate enough menu options for all buttons but since the player needs to physically hover them you could put any "padding" buttons offscreen if you need to allocate more buttons than you'd physically use)

(actually maybe it would be easier to handle the X button out of GGUI entirely - just draw a "close" button at the top-right of every menu frame and check if you're in the top right 16x16 pixels of the menu in the Mouse Left Released event, if so destroy the instance and don't even check for frames)


There's more stuff you could do here, like playing the "menu move" sound when you detect that you changed either menuvalue_x or menuvalue_y, but this should be a good starting point.

(+2)

Thank you so much Yal! I can't believe the thoroughness and speed of your replies :) 
This is a great start for me, I'm very new, and still making sense of your scripts/variables in my head. I'll be sure to implement this mouse implementation  once I get a better grasp of the overall engine.

I was wondering is there a PDF for it or just reference the features mentioned to edit it & thank you

(+1)

There's no manual, no. Great idea though, I'll see what I can do!

Thanks

(+1)

i would also love a manual. with some simple tutorials on adding mons, setting up tilesets, stuff like that. great template though! i'm loving this

Hello, question! I want to change the height and width to 1200 x 800 ( or full screen ) so i can play on a bigger screen. Now is my question where i have to start to make it work? I know i can change the height and width of the room, but which another things i have to change?

Thankyou.

(1 edit)

The majority of GUI elements are based on the VIEW_W and VIEW_H macros, update those to match the desired screen size and a lot of things should "just work". (Battle elements and some misc stuff use the room size for positioning instead so make sure to update all "1x1 screen"-sized rooms like battle, evolution etc to match the new size). Also on overworld rooms, the viewport size + camera follow border size needs to be updated, since views are set up in the Room Editor instead of by code and they're all hardcoded to 640x360 / 320x180 right now.

You might need to make some sprites, fonts and other graphics elements bigger as well, since they might look weirdly tiny on a much larger screen (and you also change from a 16:9 to a 4:3 aspect ratio which might squish some things horizontally) but that's an optional UX thing and not something that's technically necessary for this to work.

Hello, once again. Quick question:

Is there way to make it so that an NPC can only be interacted with from a specific direction?

(1 edit)

Right now interactions are handled in obj_player's step event, lines 81-98 (the block starts with a comment that reads "//Interacting"). It's a basic collision_circle check so there's two ways you could solve it:

  • Hacky way: make the object alter its collision mask depending on how the player is facing, so it has zero collision-able pixels when they're facing the wrong way.
  • More stable way: have the interact_script of that object check the player's facing, and simply do nothing if they're facing the wrong way (so you trigger interactions but they only start cutscenes/etc if the player is facing the right way). You might need to make a custom object for these directional NPCs to have an easier time overriding the regular behavior.

Hello - me yet again with another question coupe of questions. 

1) What would be your advice for setting up multi hit attacks e.g fury swipes, double slap

2) What would be the best way to make a move that gets more powerful if used in succession e.g rollout, fury cutter

(1 edit)

2) Is the easiest... since you've got access to the user's object instance you could add two local variables to obj_battlemonster, the last move used and how many times it has been used in a row; the times-in-a-row counter would be incremented by 1 if you use the same move as last time, otherwise reset. (You might also wanna reset it on switching, if you use an item, fail to act due to ailments, etc). You'd add a new "stronger if used in succession" flag to the move data and compute_damage would take the times-in-a-row counter into account if the move has the flag set.

1) Probably also is easier with new movedata fields; min/max number of hits. (Two separate fields if you want to allow moves to have a random number of hits - then you'd pick a random number between these with irandom_range. Moves that always hit the same number of times would have the min and max values be the same)

Where to insert this is a bit trickier, you could slate multiple actions but that duplicates messages and would run ailment checks multiple times. Another idea could be to make a separate "multi-hit deployer" object which is spawned after the regular damage/side effects block when the current attack has multiple hits; it would be a child of parent_battleturn so the turn doesn't automatically proceed, and would have a copy of the user/target data, the index of the move being used, and a counter of how many more hits it should cause. Whenever there's only one parent_battleturn left (remember, we're one too so the counter won't hit zero), it would run a copy of the damage/side effects code (ideally you might wanna break that out into a script to make it easier to keep adding new things in the future rather than actually duplicating it in two places ?) using the user/targets/move data it got a copy of, decrementing its hit counter each time, and if all targets are dead or the hit counter reaches 0, it destroys itself.

Hey, thank you so much for this engine:) I am learning a lot from it, all your stuff here on itch.io looks totally awesome! I also read through all the questions here to learn even more about the engine!

Also, as an advice for other mac users considering buying this:  This code worked fine on my mac, but to get it running you have to open and save it at least once in windows. Thats at least how it was for me!

For now, I have two questions: 

1: I would like to implement a minigame when the enemy attacks, kind of like Undertale. Depending on how many times the opponent hits during the minigame it would cause the player damage.  Is there a way to implement something like this?

2: Next to four attack moves I would like to also give the player four dialog options, giving the player the opportunity to either fight or talk their way to success during battle. Any Idea how I could implement this in an easy way?

Thank you so much in advance!

(+1)

Intriguing; I know GM is a bit weird with cross-compiling setups but I've never heard of anything like that. I guess some project paths won't get updated automatically unless you save on Windows and it was still using the ones from my computer...?

Anyway, onto your questions:

1) The attack is applied inside the loop in obj_battlecontrol's step event at line 672 (after the "//Apply to all target(s) individually" comment). The variable trg is set to each target individually; for your use-case I guess you would want to check whether that is a player or enemy character and do different things (it's the ID of a battlemonster object so just check its side variable) - for enemies you can keep the current system, but for players you'd branch out and create a minigame object instead, and it is responsible for applying damage, side effects etc depending on the minigame result. If it's a child of parent_battleturn the RPG turn flow should automatically wait until it destroys itself with no further action from your side.

(Basically add an if statement that checks if trg.side == side_PLAYER, if so create the minigame; then put the entire existing code into the else block)

If you want different minigames for different attacks, the easiest would probably be to extend the move data (see init_moves / init_move) and add a new field for "minigame spawn script" which is run when the move is performed, creating the appropriate minigame object(s) and setting parameters for damage etc.

2) I'm thinking the easiest way would be to give each enemy monster species an array of dialogue-options / script pairs, and then you start a cutscene where you immediately deploy a cc_question that uses it - basically what cis_shrine does, but you'd use a monster-species-specific variable for the menu alternatives rather than a hardcoded array; each of the scripts that are run when you pick an alternative would either display dialogue, enqueue extra attacks, or alter a "progress" variable in the affected enemy (or whatever else you want the dialogue system to be able to do)

For this system to work, there's a couple things you need to do:

  • There's two places where obj_battlecontrol's step event checks that there are no parent_battleturn instances; those checks need to be extended to also check that there's no obj_cutscenecontrol.
  • The monster data needs to be extended with a new field, the array of their dialogue options. You'd just store this as-is. (Game Maker didn't support arrays inside arrays when I made this engine so things like moves are broken up in the engine right now, but that's not a limitation anymore)
  • You'd need to add the "talk" option to the turn menu, its setup code's currently located in obj_battlecontrol's step event on line 359.
  • Figuring out who to talk to - so you can load their dialogue data into that dynamic cutscene - might require you to select a target, check out the code in mev_battle_attack_select for an example of how to do this.
(+1)

Yeah my guess was that mac needed the code saved in the most recent IDE to get it working. Anyways it works fine now!


Thanks a lot for the detailed advice, I will give it a shot!:)

(1 edit)

Hi me yet again,

When viewing a monsters status from the menu, is there any way to make it so that if you press say the up / down or left / right keys, it'll change to the next monster instead of having to back out each time and select a new monster?

Thanks

It's gonna be a bit complicated but I think this should work:

  1. in mev_pause_monsters_status, assign a new script to the script_step variable of the new menu that is created.
  2. This new script should check for left/right presses and if so do some stuff; we'll get to that in a little bit. Note that the menu objects already get_keys() every step so you only need to check the input status variables - if(k_l && !p_l) to check for a left press, etc.
  3. In mev_pause_monsters_status there's a giant block of code that creates the entire status menu. Break that out (everything inside the with loop) into a new script which takes two arguments monsamp and monid, these are the variables we use to read the selected monster's data - changing them to script arguments lets us reuse this blob of code without having to change it.
  4. In the new script, additionally add a new line of code at the top (before the call to ggui_menu_preallocate) which should be ggui_frames = 0; (this lets us reset the menu completely - if you haven't noticed it already the frames are containers for all other GUI elements and resetting the frame counter like this will override the old data with new data without the system noticing)
  5. In the now-empty with statement in mev_pause_monsters_status, add a call to that new script that just passes in monsamp and monid as the arguments, and additionally my_monster = other.my_monster so that we pass in the status menu's reference to the party.
  6. Now we can fill in those left/right events: they should first update my_monster (add or subtract 1; if below AMP_FIRST_ACTIVE or above-or-equal to AMP_FIRST_ACTIVE+PARTYSIZE_ACTIVE, add/subtract PARTYSIZE_ACTIVE to loop back to the other end of this valid range; repeat the operation if the monster in that AMP slot is empty), then recompute monsamp/monid as currently done in mev_pause_monster_status, and then finally call the menu-setup script with those values.

You can of course extend this to terminals as well, though you'd need a modified version of the left/right check step script that also knows that box the monster is in, and loops the cursor around its range.

(+1)

Great thanks for this, I'll give it whirl and see how I get on!

(2 edits)

Hello,

Maybe this is already asked but i can't find it.
Can you use your own art for the engine?

And i am learning to program / make something for myself and i think this can help me to understand more how to make a monster catching game

Thankyou

Yes, the engine is just a Game Maker project so you can replace anything you want!

(2 edits)

Hi there again. Three new questions

1) What does the total stat do inside the monster setup stat array?

2) Can a move have multiple special effects? Example Dragon Dance, raise Atk and Speed?

3) Where is the stat increases upon level up dictated?

(1 edit) (+1)

1) Stat total is the actual total stat distribution for the monster; the values inputted for the individual stats are scaled up so that their sum will equal this value. (This means you don't need to do the math to ensure all monsters of a particular tier are balanced, and the values for each stat only need to make sense relative to each other).

2) Not currently. There's a couple of ways to fix this, I think the easiest would be to rework how special effects work: currently, it's an array that must have 4 fields (or be empty) and they're unpacked into 4 separate scalar fields in the move data structure in init_move. (Chance, type, detail and severity). But you could just store the special effects array as-is when initializing the move; this lets you have as many fields in the array as you want. Specifically, you'd wanna have zero or more sub-arrays, each of which is a 4-element array with the same data special effects have now. When applying side effects (obj_battlecontrol's Step event, after the two comments "Side effects (target)" and "Side effects (user)", you'd loop over the outer of these nested arrays, and do the side-effect checks that currently exist for each element in that array (which would be a chance-type-detail-severity tuple). So for instance Dragon Dance would have the data

[
   [100,movespfx_BUFF,stat_ATK,1],
   [100,movespfx_BUFF,stat_SPD,1]
]

And to reiterate, this is an array with two elements; they just so happen to both be arrays with 4 elements.

3) Stats are always computed from the base stats, IVs, EVs and the monster's level. The final stats aren't stored anywhere, and stat points aren't added at any time. Check out monster_get_stat and the scripts it calls for the details.

Ah I see. Thank you, that makes sense. I'll check out those scripts and see what I can do there, thanks again. Another (hopefully easy one)

1) Is there a move / effect already set up to recover some HP relative to the attack i.e absorb or giga drain for example.

There is not; I think it would be pretty easy to implement though. Make a new "drain" side effect that applies to the target. When computing target side effects you already have access to the dmgdata variable (which among other things contains the actual damage dealt to the current target prior to applying side effects), and a_user, the battlemonster instance using the move, so it's pretty simple to apply a heal to the move's user using this information.

(1 edit)

Great, that's simple enough. Last question for now lol, where is the IV information held for each Mon? Is it held against each Mon or is it computed somehow? And does the way EVs and IVs work in this framework an exact copy or or there some differences?

IV and EV data are stored in the AMP data for that monster (AMP = Active Monster Party, the monster individuals that are in your / the enemy's party, contrasted to the general notion of each species). So, held for each mon.

They work a bit differently in this engine, both to make them legally distinct and make monster stats grow faster so you don't need to grind levels to beat the demo. If you wanna make them more Pokémon-like, all the stat calculations are in the stat-computing scripts we talked about a couple days ago - just change them there and it will affect all the monster stats in the game.

(1 edit)

New question. Once I've selected a move and it brings up the menu for selecting a 'target to attack' from the menu, where can I grab the monster id of the proposed target (the one highlighted in the menu) as in, the monster the player is thinking of attacking before it's confirmed? 

I'm implementing a battle cursor so that it highlights the enemy visually but I can only find the initial creation of the menu listing all the targets, not what the current proposed target is going to be based on this menu. If I'm going about it the wrong way feel free to correct me.

(2 edits)

The script mev_battle_attack_select will build this menu (listing only the targets that are valid depending on the move), and it creates an array "my_target" in the menu instance, which the menu later uses to slate the action when you confirm. Each entry in this array is the instance ID of a battle monster object, so you could just copy it (after it's been completely built) to your cursor object and then get positions etc by going through the instance IDs.

Now, your main question is how to keep this in sync with what you're selecting in the menu. It's pretty simple: script_step. Menu objects will execute this script after their regular menu-handing behavior if it's not NONE. (There's a whole bunch of these customizable behavior scripts for more complicated menus - check parent_menu's create event - but most of the time we only change script_draw)

Make a script that tells the battle cursor what the currently highlighted item in the menu is, and in mev_battle_attack_select, set the script_step variable in the menu to this script. (Heck, you could forgo the array-in-cursor entirely and just tell it to focus on an instance ID by having the menu check the array... that's probably easier?)

Also, you could use this to make the cursor automatically get destroyed when the menu is closed: in its create event and in this script, set an alarm to 2 steps. When the alarm happens, instance_destroy(). As long as the target menu exists, it will keep resetting the alarm before it can trigger, but when it's destroyed (after you confirm the target or cancel out), the alarm will run out and also destroy the target cursor.

(1 edit)

Excellent thank you for the in depth reply, I'll have a look into what you've suggested. For my next question, is there an easy way to add the 'box' functionality into the main menu instead of accessing it from a specific place etc?

Yeah, I belive just adding the menu option to the main menu should do it.

Open up the script cc_terminal and copy the code from there, except the csc_proceed() line, and then just paste it into a new script "mev_pause_boxes", then go to obj_player's Step event to find the code where the pause menu is created when you press the pause button - add a new line here that adds that new mev_pause_boxes option.

(+1)

Awesome thanks I'll try it out, appreciate the quick and professional support especially considering the sheer volume of my questions, sorry about that 😅

No problem at all!

(1 edit)

Me again lol. Another few questions which may or may not already been included, if they have if you could point me to those move examples that would be great.

1) Is there a way for a move to increase the damage of certain move types e.g like weather effects - Rain - increase water and electric moves?

2) Is there the ability for multi-turn moves where you charge on one turn and attack on the next i.e Solar Beam

3) Is there the ability for moves such as Protect where all damage is negated?

4) Is there the ability to force a move to go first e.g Quick attack

5) Is there the ability to force a critical hit?

6) Is there a way to force an attack to never miss i.e Swift

6) Is easy, just set the accuracy field to a really big number (all buff moves currently have 999 accuracy so they basically can't miss, though you might wanna go even further just to be sure).

1) There's no weather system currently. I'd probably implement this as a pair of global variables (weather type and remaining duration). At the end of every turn, count down the duration, and if it reaches zero, reset to "no weather" and display a message. Altering damage for certain types would be done in the script named compute_damage: simply check if e.g. it's raining and you use a water or electric move, and if so, change the multiplier variable accordingly. Effects like sandstorms/hailstorms dealing damage could be put in the same place ailment damage happens.

2) The easiest way to do this would be to implement a new Side Effect, I guess: the move itself does nothing, but has a 100% chance to add a "readied move" status which makes you skip the next turn's action assignment, and automatically enqueue the readied move (similar to how Sleep/Paralysis works), which would be special normally-unlearnable moves that unleashes the actual attack. These could be instance-variables in the battlemonster objects instead of something you store in the AMP data, similar to the buff array.

4) This is pretty straightforward, currently moves are added to a priority queue (with action_slate) using purely the monster's speed as the sorting factor. You'd add a new field to move data for "priority", which would be 0 for most moves but 1 for moves that strikes first; add a large number which will exceed the max possible monster speed stat (like 1000) times the selected move's priority value to the sorting factor when slating a move. (Also note you could give some moves negative priority to always happen last once this system is in place)

You'll probably need to increase BATTLEACTION_SPEEDBONUS_ITEM to 10,000 and BATTLEACTION_SPEEDBONUS_SWITCH to 100,000 while doing this, so high-priority moves can't happen before an item use or switch.

3) This would be a combination of the solutions to #2 and #4: give the protect move a high priority value (I think Pokémon gives protective moves 6 priority while Fake Out has 3, Extremespeed 2 and all other first-strike moves 1?) and make it apply a special 1-turn side effect (which is cleared when the turn ends) which just overrides the accuracy check ("if(random(100) <= acc-eva){" in obj_battlecontrol's Step event) - i.e., you check for the "protected" status (another instance variable for battlemonster objects) and if true, you enqueue a priority action that displays a message that the move failed due to protection rather than doing the regular hit chance check.

5) Currently there aren't even critical hits in the game, so I guess the easiest way to do this would be to add a "crit%" field to the move data and do a separate crit roll in compute_damage, returning an additional value, true/false depending on if it was a crit or not - this would affect the message and potentially sounds/visual effects... you'd also update the damage value accordingly, since crits could ignore defense... so you'd need to do this check early on. I think the easiest place to do this would be right before the "read level" segment: do a crit roll based on the new field (global.move_data[move,mvd_CRITCHANCE]) and if true, set def_buff to min(def_buff,1) and multiply atk_stat by 2. (And to make a crit guaranteed, set the crit chance to a number greater than 100)

Awesome, thanks for the in detail response there, the support you're giving is top notch. 

As an aside, do you have any plan to implement any new features to the framework at any point, or is what is offered now the final product from you? More curious than anything, what you've already provided is an amazing product for games like this to get off to a great start so I'm very happy with the purchase :)

I consider it done and final - the way Game Maker projects works, it would be really hard for people to just import the new features into their existing games, anyway, so I'd actively give people a problem if I messed around with it too much. If a new GM change completely breaks it, I'll release bugfixes, though. (array_length_1d is used all over the engine but has been deprecated, for instance, so that might become an issue at some point... easy to fix once you know about it, but I don't wanna force my paying customers to go through that just because I'm lazy!)

(+1)

Okay, I understand and it makes complete sense. Thanks.

(+1)

I just want to leave a big thank you. My last comment was from 2 years ago when I bought this and I've learned so much from the code. I don't use it for any (active) project, but I learned a lot about viable database structures. Keep up the good work

(+1)

Glad it could be of some use! ^__^

I see all of these engines as learning tools (after all, once you get better at coding any pre-existing code tends to feel restrictive and annoying to deal with) but I don't usually get to see people learning so much they can leave the proverbial nest and spread their wings! Thanks for coming back and telling me about it, it warms my heart :)

(4 edits)

Is there a script / function that I can easily call which adds a mon to the party? I'd also like to set it up so 2v2 is the standard, how do I go about that?

Not 100% sure what you mean with "add a mon to the party", is it a new mon or one from a box?

If the former, check out how mev_intro_starterselect_confirm does it: first get the first free AMP (=Active Monster Party) slot in the player party region, then generate a new monster there. The latter (swap out a pre-existing monster) is a bit trickier but there's code for this in mev_terminal_interact.

For multi battles, the important thing is setting the two variables global.player_side_monsters and global.enemy_side_monsters to the amount you want on each side (in your case both would be 2). Check out the scripts cc_battlestart_trainer and player_step_fill for trainer and random encounters respectively.

A new mon, like at the start of the game instead of the selector or a gift from an NPC for example, something like GetNewMon(monster) and it'd just go off and add it to the party if it can or a box if not, but I'll look into what you've said and go from there.  And I'll look into the global vars, appreciate the response. Great framework tho, I've had to do some bits for it to work at a smaller res but that was simple enough once I'd read through the code a bit.

Another question, I'd like to give items in the inventory little icons. I was thinking that I could just add this info into the init_item and then add some code to draw the icon sprite within the inventory menu, any reason this wouldn't work?

The code when a monster is caught should do basically what you want, then (find the first free slot in the party or box structure, and then copy the monster data from the enemy section to there).

And yeah, your line of thinking for item icons is exactly what I'd recommend! Just make sure to use a "scrollable sprite" type when coding the new menu element, so it fetches data relative to the current cursor position - basic "sprite" would essentially hard-code the sprite. (All the name strings in the inventory does this too)

(2 edits)

Awesome thank you. Another couple of questions:

1)  where is the flashing white cursor code located? I can't for the life of me find that. 

2) Is there a 'delete file' feature already created or any other save file management implemented aside from saving and loading? (like overwrite or multiple saves from the same file etc)

Also, if there is a better means for me to ask questions/seek support then let me know :)

Itchio messages are my preferred method of communication, it's nice when the questions (and answers!) are located next to the game for assets in particular and I check my messages at least once every day (unless something really serious gets in the way).

1) The flashing white rectangle that's overlayed on top of the highlighted menu option? It's in the script ggui_draw. It's actually drawing a rectangle with vector drawing instead of drawing an asset.



2) No. I'm kinda scared of implementing stuff like this because I always worry they'll go wrong and delete someone's progress, so I prefer leaving the responsibility to the player's operating system.

Hi, this looks really good and I've played the demo for a bit and I just had a few questions for if certain functionality is included and if it isn't is there plans for it or would the engine be extensible enough to include it with some work my side.

- item to teach a move to a monster

- more than 4 moves per monster

- Abilities, special effects that each monster possesses (passive skills basically)

Thank you

None of those are included by default, but since this is just a Game Maker project it wouldn't be impossible to include them.

  • More than 4 moves per monster would be relatively easy, just add a few more fields in the monster data structure and increase MONSTER_MAX_NUMBER_OF_MOVES accordingly. The biggest effort here would be to resize menus so more moves will fit visually.
  • Item to teach a monster a new move would be a bit more work (needing some custom menus) but ultimately you should be able to leverage the existing code for learning a move by levelling up here. You probably want some data structure for which monster can learn which moves, too (a big reason I didn't include this was because I figured it was too much work setting up a system like that which would still work for every user's use-cases).
  • Passive skills would need to be added to the monster species data, but ultimately would be similar to held items (check obj_battlecontrol's step event and look for all calls to the function "battle_item_might_affect_this" - you'd basically do the same type of checks, but for passive abilities). I.e., the skill has a trigger condition like "on damage" or "after your turn", and you check if the affect monster's passive skill has that trigger; if so, you invoke its effect script. (And then the script decides if anything happens - an ability like Flash Fire or Spiky Body only triggers its effect on certain types of moves but you would run the script every time the monster takes damage anyway and let it decide based on current attack data and such)
(+1)

Ah I see. Thanks very much for getting back to me so soon, going to give this a whirl over the weekend 👍

(1 edit)

You can make good top-down racing engine. If all your engines are like this, we will be happy to buy the ones that are potentially useful to us. It will speed up our work on new titles. In the end, there will be little of them, but at the beginning it will be a great help.

(8 edits)

Hello. I have question. You can write in turn, as you have arranged these icons in the program?

-Poison - I understand...

-Bleeding - I understand...

-Blindness - I understand...

-Immolation - when someone is on fire? Good?

-Strain - I do not understand this! When is someone tired? 

Or maybe stunned?

-Flinching - when is someone scared? Good?

-Paralysis - I understand...

???


This icons will be good?

I don't understand 5... "Strain". Could you explain to me? Because the translator translates it strange.

(+1)

Strain = lose extra MP when doing a move. (I got the idea from Shin Megami Tensei). It's basically the "Spite" move from Pokémon, but as an ailment.

(1 edit) (+1)

Like "Resentment" i think?

You think icon ZZZ is good for this?


or better this?

There will be a game when we finish ;)

https://husaria-games.itch.io/pixel-monsters

(+1)

Second icon is more readable IMO, but it's your game :P

(7 edits)

Yal... I have problem with add more monsters. I added 32 but in Monsterpedia (new name of my ...pedia) I have only 19 when I take this monster #macro monster_ORANGE_FOX 18 from start. When I take this monster for start #macro monster_FROG 22 i have 23. And when take this #macro monster_RABBIT 31 i have all 32. This 3 monsters these are the ones I choose at the beginning (NEW GAME). 

Only shows me in MONSTERPEDIA these monsters before the one on the list + his.

EXAMPLE:

When I take #macro monster_HORSE 3 (number 3) I have in MONSTERPEDIA only 4 monsters: 

#macro monster_HYENA 0

#macro monster_TIGER 1

#macro monster_GOAT 2

#macro monster_HORSE 3

Where is problem? :(


I make something like this:

On start Im take #macro monster_HYENA 0 (I have only HYENA in MOSTERPEDIA). I go fight. First monster with whom I fought it is #macro monster_BADGER 7. When I finish I have in MONSTERPEDIA 8 monsters (6 with "???" and HYENA and BADGER. Off course this "???" are a previous numbers of monsters before BADGER. And I go fight with another #macro monster_ELEPHANT 9. Now I have 10 monsters in MONSTERPEDIA. 7 with "???" (unknown) and 3 met by me. 

These "???" these are the ones in front of the elephant. It should not immediately display a list of all that are added as unknown, ie with the characters "???"?Because he only adds when I get to know (the one I meet) and everything in front of him then (MACRO is about numbering), of course, those before the known (apart from those known) are marked with "???" that is, marked as unknown. 

But it doesn't make sense. I think this is some kind of error or I am doing something wrong.

I changed your names to my monsters names. I checked everything 5 times. I missed nothing. 

Nothing else I touched except the graphics.


And I check your demo. You have this same bug in it.



-------------------------------------------------------------

//Starters

#macro monster_HYENA 0

#macro monster_TIGER 1

#macro monster_GOAT 2

#macro monster_HORSE 3

#macro monster_SNAKE 4

#macro monster_COW 5

#macro monster_LION 6

#macro monster_BADGER 7

#macro monster_DONKEY 8

#macro monster_ELEPHANT 9

#macro monster_HIPPO 10

#macro monster_RHINO 11

#macro monster_DOG 12

#macro monster_CAMEL 13

#macro monster_POLAR_BEAR 14

#macro monster_CAT 15

#macro monster_OSTRICH 16

#macro monster_MOOSE 17

#macro monster_ORANGE_FOX 18

#macro monster_PIG 19

#macro monster_SHEEP 20

#macro monster_KANGAROO 21

#macro monster_FROG 22

#macro monster_GIANT_SNAIL 23

#macro monster_HEDGEHOG 24

#macro monster_PANDA 25

#macro monster_PLATYPUS 26

#macro monster_POLAR_FOX 27

#macro monster_SKUNK 28

#macro monster_SQUIRREL 29

#macro monster_TORTOISE 30

#macro monster_RABBIT 31

//Gotta enslave them all!

#macro MONSTER_MAX 300

#endregion


--------------------------------------------------------------

///cc_intro_startermonsterselect()

function cc_intro_startermonsterselect() {

var mon, mons, xx, ww;

mons = 3

mon[0] = monster_FROG

mon[1] = monster_ORANGE_FOX

mon[2] = monster_HORSE

ww = 1/mons

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

ggui_frame(VIEW_W*0.1,VIEW_W*0.35,VIEW_W*0.8,VIEW_H*0.25,NONE)//Yeah, we can do invisible frames!

ggui_menu_preallocate(mons,1)

ggui_element_text_settings(font_mainmsg,c_black,1,0)

for(var c = 0; c < mons; c++){

my_monster[c] = mon[c]

xx = (c + 0.5)*ww

ggui_element_sprite(xx,1.00,global.monster_data[mon[c],mond_SPRITE_BATTLE],0)

ggui_element_text(  xx,1.05,global.monster_data[mon[c],mond_NAME])

ggui_menu_region(c,0,mev_intro_starterselect,xx - 0.5*ww,1 - ggui_frame_get_coord_y(128),xx + 0.5*ww,1)

}

menu_can_destroy = false

}

}

(1 edit) (+1)

Only monsters you have seen get added to the list, it ends with the last monster you have registered:

If you want the entire list to be visible immediately, you could remove this loop and set maxmon to the value MONSTER_MAX-1 instead.

I was wondering do you plan to make a Yu-Gi-Oh type engine, card collection I think if you modified this one it might work into it

No plans, sorry. (The hardest part with making a collectible card game is making all the rules, and that's a very per-game-specific thing that's hard to make a general system for)

Understood

Deleted 1 year ago

I'm just checking the update has the entire source code correct because I need to modify it, & you need to make some tutorials either a video with text or PDF so I can understand how to use it better thanks 👍

Yeah every update has the entire source code (it's the entire GameMaker:Studio project file)

(1 edit)

Hey Yal, I'm wondering if you could help me on what to do for making moves that can do the following:

-Metronome like effect, completely random move

-A random move from a specific type (Example: Channel, uses a random Ghost type move)

I'd also like to make one that deals a random status effect, a random move from a list of specific moves, and a random stat lower or raise, but those ones I could probably figure out on my own once I know how to make those two. Also, I guess the metronome like move would need a blacklist so you don't pull out a boss-only move or something.

The answer to all of them basically boils down to "make a list of all moves and then pick a random entry from the list"... for very narrow categories you could build these lists manually, but for large lists (e.g. Metronome specifically) you could do this automatically: loop over all moves (after you've defined them in init_moves) and add the move ID to the list if it's valid (you could check validity using a new "valid for metronome" property, or your own list of invalid moves)

Now for the tricky part, when to do the table lookup and how to work it into the move system... I think this would be the easiest way:

  • Make the move target the user (movetarg_USER), be of movecat_SUPPORT category, have no damage, but a 100% chance to trigger a special effect
  • The special effect is of a new movespfx_METRONOME type, the "detail" field could be a reference to which random list of moves to pull from
  • When the side effect is rolled (battlecontrol step event, line 778 onwards ("Side effects (user)"), you action_enqueue_prio the new move you pick from the list (thus making it be performed immediately instead of being scheduled based on the Speed stat). You can use battle_get_random_targets() to get a random valid target for the move, see the bcontrolstate_ACTIONSELECT_ENEMY section at line 393 onwards where it selects moves from the AI.

Hey Yal, thanks a lot for this engine !

I'm actually trying to change how the battles works, but as a beginner I'm a bit lost on how the moves works.

Instead of the menu I would like to assign each attacks to one button, and the monster taking the damage if they were touched by an hitbox, but I don't really understand how to call for these moves. I guess it's about the amp_moves but I don't really know how. 

sorry for the specific question ^^

Move IDs are stored in global.active_monster_party[amp_id,amp_MOVE1] through global.active_monster_party[amp_id,amp_MOVE4] and then move data is stored in the global.move_data array.  So after you get a move ID from amp_MOVE1...amp_MOVE4 you can look up global.move_data using the ID you looked up and the move data constants (they begin with the prefix "mvd_")

Deleted 1 year ago
Deleted 1 year ago

Game Maker has support for networking, but I've never managed to get online multiplayer to work myself so I'm afraid I can't offer much help here.

Engine-wise I'm thinking you'd have the other player act like an AI player, and then their moves are based on what the player selects, with netcode synchronizing player inputs... you'll also need to make the RNG shared so things like variable damage and chance-based effects will be the same for both players.

(1 edit)

I have several questions

1. how do I change what ev's a monster gives?

2. how do I make items that make specific monsters learn a move like tms?

3. is there a way to make monsters give less exp when deafeated?

4. I tried making battles 2v2 but right now if the player only has one the game crashes, and I couldn't get the enemy to have 2 without crashing

5.  is there a wat to make a certain encounter with a monster have the monster have set ivs?

6. right now I can't find a way to view the move descriptions

7. how would I exclude some monsters from the monsterepeda?

8. I found a bug: after you run from a monster if you press the main button a bunch it will take you to the spot where the player character is in the room

9. how would I make a monster that evolves into 1 of 2 monster randomly?

10. is STAB implemented? and if not how can I put it in?

1. There's a stat for this in init_monsters, search for "mond_EVBONUS_STAT".

2. This is a bit tricky, but the basic steps would be:

    - Create a new itemtype + usescript (check out init_items for the context for what these means) and add the new items to init_items

    - The usescript first checks if the monster is compatible (if you want to have a check like this) and then does something similar to mev_monster_learnmove_spawnmenu (check out obj_battlecontrol's step event at line 1022 to see how it handles whether the monster has empty move slots and can learn moves immediately).

3. EXP calculations are done in obj_battlemonster's step event, line 94. Currently it's based on the monster's levelup EXP but you could add a new stat to the monster data for this for instance, or just lower the factor from 0.1 to something lower.

4. What's the crash error message? Player monster slots should start as KO'd if there's not enough monsters left that can fight, and you need to generate enough enemy monsters to fill all their slots. Check player_step_fill line 33 for how horde battles are generated currently.

5. Check out obj_npc_trainer's User Event 0, line 11 onwards it generates monsters. You could do something similar with a new "set encounter" object which generates new monsters and then overrides anything you want to change. (I assume you want to use this for legendaries so it'd also set the battle mode to wild instead of trainer)

6. It's currently only used in the learn new move menu (mev_monster_learnmove_spawnmenu), I guess I forgot to put it in when making the pause menu...

7. The easiest way would be like this:

    - Add a new constant before MONSTER_MAX named MONSTER_PEDIA_MAX which has a lower value

    - Go to mev_pause_moncyclopedia and change the first loop to end at MONSTER_PEDIA_MAX-1 instead of MONSTER_MAX

    - Give all excluded monsters an ID number between MONSTER_PEDIA_MAX and MONSTER_MAX

8. I don't understand your explanation.

9. I think something like this could work:

    - Create a new evolution type "evotype_RANDOM"

    - Every monster that has this evolution type has an ARRAY of evolution monsters (third slot in the evolution data)

    - amp_earn_exp checks for levelup evolutions, after line 40 add a new case that checks for evotype_RANDOM, and if the level requirement is met, sets evo to: global.monster_evolution_mon[ monid][c][irandom(array_length(global.monster_evolution_mon[ monid][c])-1)]

10. Yes, it's computed in the script compute_damage, line 50.

(1 edit) (+1)

Man do you know How amazing you are?

This is perfect 

(1 edit)

How do I change the capture rate of each individual monster? and how to change how much exp each monster gives?  also, how do I make battles have more monsters?

  1. Check out itemuse_catch, which computes the catch rate for a given stone. Currently it's the same for all monsters, but you could add a new "catch rate" stat for each species (see init_monsters / init_monster), and then get the species data using the AMP_ID. (i.e.,  something like global.monster_data[global.active_monster_party[amp_id,amp_MONID],mond_CATCHRATE] )
  2. Currently EXP is computed in obj_battlemonster's step event, case 30 (bmonsterstate_DIE), using the same formula as levelup EXP (script monster_get_next_level_exp), which in turn is based on the monster's EXP group. Easiest way to influence this is adding more EXP groups, but if you want full control you could add an "EXP loot" stat just like the catch rate, and use that. (You probably want something that scales with the level, but of course it depends on how you want your game to work)
  3. Check out the variables global.player_side_monsters / global.enemy_side_monsters (set them to the number of monsters you want each side to have before you start the battle - currently this is done in the script player_step_fill)
(1 edit)

Is there by chance already a system to exclude encountering monsters that are currently in your party? I seen the possibility of doing something within the ects_placeholder function, but with out doing a bunch of if statements?

(1 edit)

There's no built-in system, but it should be easy enough to set up.

In obj_player's collision event with obj_encounterzoneselector, after line 8 insert some new code:

for(var b = 0; b < array_length(global.encounter_valid_monsters); b++){
  for(var c = AMP_FIRST_ACTIVE; c < AMP_FIRST_ACTIVE + PARTYSIZE_ACTIVE; c++){
    if(global.active_monster_party[c,amp_MONID] == global.encounter_valid_monsters[b]){
      array_delete(global.encounter_valid_monsters,b,1)
      b-- //Deleting shifted everything back one step so re-check
      break;
    }
  }
}

(this is completely untested so use with care)

the encounter_valid_monsters array is common to all ects_* (EnCounter Table Setup) scripts so modifying it directly like this means it should work everywhere in the game.

Thank you. So far after testing it's worked perfectly. One more thing. What would best way to go about have a "Release Monster" from party in status menu? Thanks again for the help.

Call amp_clear_monster() on its AMP ID to reset a monster's data (AMP = Active Monster Party is the list of "currently loaded" monsters, e.g. party, boxes and enemies). 

Sorry to bother you again, but still learning. I'm struggling on updating the monster part list. Maybe you can point me in the right direction on what I'm missing. This is what I have:

function mev_pause_monsters_release_confirm() {     with(instance_create_depth(x,y,depth-1,obj_gguimenu)){         daddy = other.id         message_spawn(tsprintf(                 "You released %.",                 amp_get_monster_name(other.my_monster)))         amp_clear_monster(other.my_monster)         with(daddy.daddy){             if(object_index == obj_terminalmenu){                 msh_terminal_update()             } else {                 msh_spawn_monster_list()             }         }         instance_destroy(daddy)         instance_destroy(daddy.daddy)     } }

It looks pretty reasonable, but you both update and delete daddy.daddy... I think you meant this? (destroying the "are you sure?" menu and the "what do you want to do?" menu)

instance_destroy()
instance_destroy(daddy)

(also of course you need to set my_monster to the AMP_ID (index in the Active Monster Party array) of the monster you want to delete when you create the menu that eventually runs mev_pause_monsters_release_confirm() , so the variable has a valid value... I presume you're doing this?)

Well after further testing it does break after you catch all the possible monsters for that zone.

(+1)

One way to fix that is to add some code setting the step range really high if the list of monsters is empty:

if(array_length(global.encounter_valid_monsters) < 1){
  global.encounter_step_range     = [9999, 9999]
  global.steps_to_next_encounter  = 9999
}

For additional stability, go to player_step_fill and add an if statement around line 10 to not count up encounter steps if the limit is 9999:

if(global.steps_to_next_encounter < 9999){
  encounter_steps++
}

Thank you very much for all your help. That worked and was a much easier solution then what I was thinking.

Hey, how would I go about adding abilities to the game, for example stuff like Water Absorb that heals you when hit with a certain type of attack?

Easiest way would probably be to add a new argument to init_monster which is supposed to contain an array with at least four elements; trigger constant, trigger function, name string, and description string (the last two are optional but you probably want them for the status screen later), and then go through init_monsters and make sure every monster gets an ability. (Of course you need to define new "mond_" constants for these new data points and increase MONSTER_DATA_MAX accordingly, on top of adding the trigger constants and making some scripts)

The idea is that you add triggers wherever an ability could affect something: every turn, on damage, when first entering battle, etc. Check if the monster in question has the matching trigger constant, and if so, run its script. For your Water Absorb (and Flash Fire, Lightningrod, etc) example specifically, check out obj_damageapply's Alarm 0 event, near the bottom:


You'd basically want a check like this, but for the monster's ability instead of its item. (And since it might potentially cancel out damage, you want it at the TOP of the event instead - the "water absorb" ability effect script would set my_dmg to a negative value before it's applied, so it becomes healing)

Side note: if you want monsters to potentially have different abilities, you should also add ability slots to the "amp_" (Active Monster Party) system, and make amp_generate_monster pick a random ability out of the available choices from the species data (and of course, you look up AMP data instead of MOND data when you check if the ability applies). If you're gonna reuse abilities a lot you'd probably want to make a whole ability data array and have references to that instead of storing the entire trigger+script+name+description per-monster. But one step at a time!

Maybe a bit of a weirdly specific question, but I was thinking of pokemon like Spinda, where their markings are essentially randomly placed. Usually I would do this with a clipping mask and a random x and y coordinate when drawing the sprite, but I was curious if you knew off the top of your head if this would work? I would probably need to add the X and Y variable to the individual monster, and use that?

I think the easiest way to do things like this would be to expand global.monster_data and add a "draw script" field. Whenever the monster is drawn, invoke this script instead of just draw_sprite/draw_sprite_ext (you can find all cases where a monster is drawn by doing a project-wide search for the "mond_SPRITE_BATTLE" constant). For monsters that don't need any special drawing, you'd add a default script that just draws the sprite like normal.

This is gonna be a bit tricky since a lot of the drawing is in menus (shrine terminals, status screen etc) so you'd probably need to add a new type of GGUI element that contains both a sprite and a script to draw it with (right now monsters are drawn in menus by creating a sprite element containing their sprite).

For the random markings themselves, the easiest way would be to use random_set_seed() and construct the seed from something that's unique to the monster and won't change - e.g. some sort of hash of their IVs (or you could give them a new "ID number" field set to like, irandom(9999999) when generated with amp_generate_monster() if you think that's easier), then generate the random coordinates to draw with, and finally randomize() to reset the RNG again. This way, the random numbers will always be the same for the monster, but you don't need to store them in any way.

Thanks so much for all your super in depth answers, it's always helpful!

Curious because I couldn't see any built in function for it, what would be the easiest way to change text speed temporarily? To give the effect of someone speaking slowly, for instance.

Secondly, I don't see an easy way to do this in your code anywhere, so I was curious about "gift" monsters. I.E. an event that just straight-up gives one specific monster upon talking to someone.

Thanks again so much for your responses.

(1 edit)

Gift monster ID's easier, so let's start with that.

Try amp_get_new_party_id to get the ID of the first empty slot in the party. If NONE, there's no empty slot - either abandon the gift procedure and tell the player they need to make some room in the party, or amp_get_new_box_id to get the first empty slot in the storage system instead. When you've got an empty slot, use amp_generate_monster to actually create a monster. (And optionally, give it a held item, special moves and so on - check out all the fun stuff in Scripts --> Data Mangling --> Active Monster Party). Also call msh_recompute_seencaught, in case the player didn't have this monster dex-ed yet.

(You can see an example of this stuff in action if you check mev_intro_starterselect_confirm.)


Now for text speed: There's two places where text speed is used, both in the message_handle script.

Line 17:

for(var c = 0; c < 2 + 2*k_a; c++){ //(main speed control - this many letters are typed per game step)

and line 23:

message_cooldown += 10; //(temporary pause on detecting the "|" character)


Depending on what needs you have, you could change either of those to put in some more speed control. I.e. instead of typing 2 + 2*k_a letters per step, you could type global.text_speed*(1 + k_a) letters, where the text speed variable defaults to 2 but there's a new "cc_textspeed" cutscene command script (see Scripts --> Cutscene System --> Cutscene Commands) which lets you change it at will. (I.e. change it to 1 to type more slowly, or change it to 99999 to reveal text instantly (but | characters can still be used to add dramatic breaks))

And of course, if you just want to add dramatic breaks or show someone enunciating a word extra clearly, there's no need for extra code - you could just sprinkle in some |s - one between each letter |l|i|k|e| |t|h|i|s, or a bunch at once when someone's...||| catching their breath.

(+1)

Ahhhh thank you! Somehow I COMPLETELY missed the AMP scripts in data mangling, so I was just going around in circles for a few hours.

Curious if there's any breeding mechanic built in, or if it would be relatively easy to add one?

There's no breeding mechanic built in. It probably wouldn't be TOO hard to add one, but still pretty involved:

  • Set up "egg groups" and assign monster species to them. Not sure what's the best way here, but since you won't check them very often you don't need to worry about performance.
  • Add a daycare (or somesuch) where you can deposit monsters. Easiest way would be to functionally add a new storage box, which can't be accessed from the shrine PCs. Every time the player takes a step, you could loop over every monster in this box and give them EXP (if you wanna copy Pokémon wholesale), but you'd also tick up some daycare counters every time you reach a step threshold (256 or something)
  • When monsters of a matching egg group are in the daycare, each Egg Tick you'd roll a random number to see if it's time to create an egg. 
  • I think the easiest way would be to have an "egg flag" in the AMP data, which is true for eggs and false for other monsters. If the egg flag is true, the monster is considered fainted (so it can't be sent out) and checking its status will give you a special screen with the hatching info. The moment you generate an egg in the daycare, you actually generate the lowest evolution of the mother (and put it in another slot in the Daycare Box - or if you want to be able to generate more than one egg at a time, you might want to have a special Egg Box instead), and then just sets its egg flag to true. (You could also manually overwrite data for things like inheriting IVs, Egg Moves and so on)
  • If the player has any eggs in the party, you'd reduce the hatch counter for every egg in the party every Egg Tick, and if an egg hits zero, abort the loop and go to a hatching sequence (which you'd handle similar to how the monster evolution works now: set the load position, change rooms, go back to the room you were in when it ends).

Is there a way to make a sign display the players name?

(1 edit)

Yeah, just include the value of global.player_name in the message.

Easiest way would probably be to make a new type of signpost (a child of the obj_signpost so it "just works" with the existing interaction code) whose interact_script is cis_npc_polyliner and then give it a new expression-typed variable "my_messages". For each sign you place you'd then give it a messages value like:

[tsprintf("This is %'s house!",global.player_name)]

(So it contains an array of strings, with only 1 value - this is different from just a regular string, since cis_npc_polyliner loops over the array of messages, so don't forget the []'s around it)

(The reason the default signpost doesn't work is that it has a string-type variable, so it'll just include the variable / tsprintf call as text instead of running the code. You could of course change it to expression-type in the base sign instead, but that breaks all existing signposts unless you manually add quotation marks around their text...)

(+1)

Your the best thank you.

i get this when i do what you sugested. 

Instance Code in Room: rm_overworld_5 at line 1 : invalid token '

Undefined variable 'This' referenced in room rm_overworld in instance inst_16EAE0C0's variable 'my_message'

Undefined variable 'is' referenced in room rm_overworld in instance inst_16EAE0C0's variable 'my_message'

Did you:

  1. turn it into an Expression variable?
  2. put quotes (") around the text?
  3. put square brackets ([ at the start, ] at the end) around the resulting string?

The error message makes it sound like it's trying to interpret plaintext (the stuff that's supposed to be in a string) as an expression so it sounds like you missed the quotes.

I copied exzactly what you had typed. Maby i missed where i need to change to an expresion var

It should look like this:

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