Comments

Log in with itch.io to leave a comment.

Viewing most recent comments 1 to 20 of 80 · Next page · Last page

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

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

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

(1 edit)

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

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

(+1)

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

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

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

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

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


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


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

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

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

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

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

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

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

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

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

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

instance_destroy(daddy)
instance_destroy()

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

(2 edits)

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

(1 edit) (+1)

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

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

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

(+1)

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

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

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

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

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

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

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

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

(1 edit)

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

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

(1 edit)

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

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

great short cut thank you!

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

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

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

Ok thank you I shall attempt this!

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

(+1)

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

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

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

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

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

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

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


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

Also make sure the tileset settings are correct!

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


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

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

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

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

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


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

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

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

Are you going to continue working on this soon?

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

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

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

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

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

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

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

var d, mev, it;

draw_set_font(font_n)//Needed by string_wrap

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

vev= d

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

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

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

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

if(global.monsters_caught[d]){ 

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

mev = argument0

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

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

var soul = global.monster_data[d,mond_CRAFT_SLOT_SOUL] 

shop_item  = it

shop_cost  = soul

    

}

function msh_botsmith_spawn_monsterpurchse_list(argument0) {

//mev_pause_moncyclopedia()

//Make sure statistics are up-to-date

msh_recompute_seencaught()

//Find max monster

var maxmon = 0, c;

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

if(global.monsters_seen[c]){

maxmon = c // maxmon is arraylength

break

}

}

    show_debug_message(global.monster_data)

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

ggui_menu_preallocate(1,maxmon +1)

//Left pane: monster list (scrollable)

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

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

var cmax = 10, yy, hh, vev;

ggui_element_text_settings(font_mainmsg,c_white,0,1)

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

vev= c

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

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

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

}

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

var d, mev, it;

draw_set_font(font_n)//Needed by string_wrap

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

vev= d

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

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

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

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

if(global.monsters_caught[d]){ 

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

mev = argument0

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

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

var soul = global.monster_data[d,mond_CRAFT_SLOT_SOUL] 

shop_item  = it

shop_cost  = soul

    

}

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

else if(global.monsters_seen[d]){

mev = NONE

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

shop_item[d] = NONE

shop_cost[d] = 0

}

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

else{

mev = NONE

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

shop_item[d] = NONE

shop_cost[d] = 0

}

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

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

}

//Upper right pane: monster sprite + name

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

ggui_element_sprite_current(0.5,0.8)

ggui_element_text_settings(font_mainmsg,c_white,1,0)

ggui_element_text_current(0.5,0.8)

//Lower right pane: flavor text

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

ggui_element_text_settings(font_n,c_white,0,0)

ggui_element_desc_current(0.1,0.1)

//Lowest right pane: total statistics

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

ggui_element_text_settings(font_nfat,c_white,1,1)

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

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

}

}

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

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

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

(1 edit)

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

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

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

Hi Yal

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

 What should I do, what am I doing wrong

 I am asking you for help

Hi Yal

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

 What should I do, what am I doing wrong

 I am asking you for help

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

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


Thanks! ^.^

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

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

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

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

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

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

Thanks Yal

(1 edit)

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

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

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

(1 edit)

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

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

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

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

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

should be changed to

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

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

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

(1 edit)

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

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

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

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

(1 edit)

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

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

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

(1 edit) (+1)

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

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

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


//Damage

if(pow > 0){

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

if(sheildcheck >0){

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

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

n.my_mul = dmgdata[1]

n.my_eff = dmgdata[2]

n.my_mon = trg

n.my_user = a_user

n.my_move = a_comm

n.this_is_an_attack = true

}

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

if(sheildcheck < 1){

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

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

n.my_mul = dmgdata[1]

n.my_eff = dmgdata[2]

n.my_mon = trg

n.my_user = a_user

n.my_move = a_comm

n.this_is_an_attack = true

//User might hold an item that improves attack effectiveness

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

var it = amp_read_var(a_user.amp_id,amp_HELDITEM)

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

}

}

}


Thanks!!

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

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

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

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

Hello again,

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


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

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

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

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.
Viewing most recent comments 1 to 20 of 80 · Next page · Last page