Comments

Log in with itch.io to leave a comment.

Viewing most recent comments 1 to 14 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)

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 14 of 74 · Next page · Last page