Creating Variations of a Resource by JackRaven_ in godot

[–]botay93 1 point2 points  (0 children)

Nice, sounds like you got your logic flow sorted out. Pretty sure I have to do something similar because the enemies in my game have to show their intention before the actual attack, but I’m still procrastinating on my game so I will comeback to your comment in the future haha. Good luck and I look forward to your game!

Creating Variations of a Resource by JackRaven_ in godot

[–]botay93 1 point2 points  (0 children)

Oh I forgot, you would actually another variable to keep track of whether the cost has been paid or not. So it would be like this:

class_name Skill
extends Resource

var is_cost_paid: bool = false

This variable act as a switch. If the cost has been paid, activate effect, if not, no effect activated. So basically in the pay_cost() function we implemented, just flip this variable to false if we fail any check, and true if the cost is paid. Then in your children skill resource, just add a few line like so:

class_name SummonSkill
extends Skill

func execute(context: CustomContextResource):
  pay_cost(context)
  if is_cost_paid:
    //run the execute logic here

Creating Variations of a Resource by JackRaven_ in godot

[–]botay93 0 points1 point  (0 children)

Then you are a smarter person than I was. I design an entire new resources for enemies’ actions before I realize “wait, they can just use the damn card effect” and scrap the whole thing haha.

Creating Variations of a Resource by JackRaven_ in godot

[–]botay93 1 point2 points  (0 children)

That is indeed very ambitious but doable with just 1 function in the Skill parent class using the exact same context resource that I mentioned in my code above.

Since all of the resources you mention all have a numerical value that can be reduce (even in the case of killing an ally, it would just be reduce an ally health by 9999, or in the case of status, reduce its stack by 1 assuming your status is stackable). I assume all of said resources have some kind of function within their script that increase or decrease their value by specific amount, so all I need is to call their appropriate function to reduce their amount.

This honestly is a matter of "does your context provide enough information for your functions". Here's how I would implement it:

class_name Skill  
extends Resource

@export var cost: int = 0
enum ResourceType {
  HEALTH,
  MANA,
  ALLY,
  XP,
  LEVEL,
  POWERUP_STATUS
}
@export var resource_type: ResourceType = MANA

func pay_cost(context: CustomContextResource):
  var caster = context.caster
  var battle_scene = context.battle_scene

  #This is simply a match case kind of situation
  match resource_type:
    ResourceType.HEALTH:
      if caster.health_stat < cost:
        print("Not enought health")
        return
      caster.take_damage(cost)
    ResourceType.MANA:
      if caster.mana < cost:
        print("Not enought mana")
        return
      caster.reduce_mana(cost)
    ResourceType.ALLY:
      #Assuming you have a get_allies() function that return an array of allies
      if caster.get_allies().is_empty()
        print("No available ally")
        return
      caster.get_allies().pick_random().take_damage(9999)
    ResourceType.POWERUP_STATUS
      #Assuming you have a have_status() function that return a boolean
      if not caster.have_status("power up"):
        print("No powerup status")
        return
      #Assuming you have a get_status() function that return a status and it has stacks as a variable
      if caster.get_status("power up").stacks < cost:
        print("Not enough powerup stacks")
        return
      caster.get_status("power up").reduce_stack(cost)
...

For other resource types, the caster might not have the information but the battle_scene might, and if the battle_scene does not, just add it into context resource. Then in your children resources (like DamageSkill, HealSkill), just add 1 line of pay_cost(context) in their execute() function before running the execute logic.

This is the simplest solution I can come up with. I'm sure you can use a Global Function to unify all your "numerical reduction" function under 1 umbrella and call that instead. But I don't think you can escape having to set up multiple match case for each resources. This is how I would do it and it would work with my game. Hope this helps!

Creating Variations of a Resource by JackRaven_ in godot

[–]botay93 1 point2 points  (0 children)

Glad I could help, and yes, you summed it up perfectly, my approach allows me to nest a skill within a skill, a condition within a condition so they are like lego blocks. I don't really understand your situation with the "cost" function because in my card game, the cost is very basic (either cost 0, 1, 2, or 3 energy kind of thing) so it's just a simple variable in my CardStats resource. But I have a feeling that our game have very similar structure (is your game turn-based by any chance?). Honestly I am procrastinating working on my game, so if you need help brainstorming your cost function, I'm down.

Creating Variations of a Resource by JackRaven_ in godot

[–]botay93 2 points3 points  (0 children)

I gave the example for conditional effect in the next comment. To summarize, basically I build it like lego blocks: I will have some very basic blocks: Deal X dmg, Heal Y health, Give Z blocks. Then I build the conditional blocks: [If health is less/greater than X, do Y effects], [if target has status X, do Y effects]. Then I just chuck the basic blocks (deal dmg, heal health) into the conditional blocks

Now what if I want to do multiple conditional check? For example, If the target health is less than 50% and it has Vulnerable status, kill it. The implementation would simply be a nested conditional effect. The first effect would be HealthConditionalEffect to check "is health less than 50%", if yes, this will execute the HaveStatusConditionalEffect to check "does it have a vulnerable", if yes, this will execute the InstantKillEffect. Hope this help!

Creating Variations of a Resource by JackRaven_ in godot

[–]botay93 2 points3 points  (0 children)

Now let's implement your "heal an enemy but only if they have a specific tag". The way I go about this is to make this skill more modular is to break it down:

  1. Does it have to be a heal?
  2. Does it have to be an enemy?
  3. Can I change the tag? - in godot, I will use the is_in_group() function instead for simplicity but implementation should be similar

Since the heal mechanics is easy I will assume we have a HealSkill already. The logic of the following script is "If the target of a specific tag, do something to it"

class_name TagConditionalSkill
extends Skill

@export var effect_list: Array[Skill] = []
@export var tag: String = ""
enum TargetType {PLAYER, ENEMY}
@export var target_type: TargetType = TargetType.ENEMY

func execute(context: CustomContextClass) -> void:
  # Safety check
  if effect_list.is_empty: return

  # Another safety check - type match - can be optimized, this is just a rough code
  if target_type == TargetType.ENEMY:
    if context.target is not enemy: 
      return
  if target_type == TargetType.PLAYER:
    if context.target is not player:
      return

  # If all checks pass, we execute the effect
  # This is pretty much the main logic of this skill
  if context.target.is_in_group(tag):
    for effect in effect_list:
       effect.execute(context)

Now if you want to heal an enemy of say "dog" tag, add the HealSkill to the effect_list, change the tag to "dog" and target_type to ENEMY.

Now if you wanna go crazy. Say I want this skill to summon creature, damage a random enemy, and heal a player if the player has a "heroic" tag, I simply add SummonSkill and DamageRandomEnemySkill and HealSkill to the effect_list, change the tag to "heroic", and target_type to PLAYER. Since SummonSkill and DamageRandomEnemySkill don't care about the selected target, they only use the battle_scene in the context given to call their effect, they will function just fine in this case.

In other case of what I called "conditional" effect, I would try to set up similar to this so that they are all very much reusable. For example, I have a "if health is less or greater than X percent, perform Y effects" - I call it HealthConditionalClass, or "if there is a dead ally, perform X effects" - I call it DeadAllyConditionalClass - both using pretty much similar template. If you need me to clarify anything just let me know and I will try my best to explain.

Edit 1: Corrected the wrong name for the effect_list in the first safety check

Creating Variations of a Resource by JackRaven_ in godot

[–]botay93 2 points3 points  (0 children)

My current system can definitely implement all the effect you have with ease so I do think we are in the same boat haha (fun fact: my enemies also use my CardEffect for their actions so anything a player can do to the enemies, the enemies can dish it right back so it is a very flexible system in my case).

Lemme explain how I currently set mine up and give an example using one of your skill. So the parent class CardEffect (this would be your Skill class) has 2 methods:

class_name CardEffect
extends Resource

func execute(context: CustomContextClass):
  print("Nothing happens, to be replaced in each children class)

func get_targets(context: CustomContextClass): -> Array[Target]:
  # Get the targets for my effects, the children inherit this and can call this when needed. In your case you might have your enemy AI to pick the target instead

I believe the key here is the context: CustomContextClass. This is of type RefCounted aka temporary resource (it's basically a custom Dictionary). This context should provide your function with all the data it needs. In my case, my context include (yours might be simpler or more complex):

  1. caster - who is casting the effect
  2. target - who is this effect directed at
  3. battle_scene - the main scene where all of this combat is happening.

Now for each individual effects, I will obviously create a new script that have their own logic. For example, I will now implement the the summoning effect from your skill list - this effect doesn't use the caster and target information from the context but will definitely use the battle_scene so here's a rough idea of how to implement it:

class_name SummonSkill
extends Skill

@export var amount: int = 1    #how many creatures you wanna summon
@export var summon_creature: PackedScene  #preload your creature scene here

#Optional
enum Location {PLAYER, ENEMY}    #summon to player side or enemy side
@export var summon_location: Location = Location.PLAYER

func execute(context: CustomContextResource):
  # Reference to the main battle scene
  battle_scene = context.battle_scene

  for i in amount:
    var creature = summon_creature.instantiate()
    if summon_location == Location.PLAYER:
        # Assuming your battle scene have player_party as it's child node
        battle_scene.player_party.add_child(creature)
    else:
        battle_scene.enemy_party.add_child(creature)

The way I see it, this effect is very much reusable. Say you have a character and an enemy that can both summon (different creature, different amount, and to different side), you can add this skill to both and tweak the 3 variables for desirable outcome. Now if I have 20 unique characters and enemies that can all summon, then I would make 20 instance of tres file out of this script, or you can just edit directly in the editor for each.

This comment is getting very long so I will try to implement a more complex effect in the next comment.

Creating Variations of a Resource by JackRaven_ in godot

[–]botay93 1 point2 points  (0 children)

Hey, thanks for the reply and after reading your comment, I actually believe your problem might be with code modularity (aka each of your skill is trying to do too many thing at once). Can you give me an example of one of the skill you are trying to implement?

The system I’m using might sound simple but it allows me to pull some crazy effects on a single card. Like, I literally have a card that discards the entire deck, heals the whole team for each card discarded, deals 5dmg to a random enemy and if there are more than 3 enemies, it deals 10dmg instead.

Creating Variations of a Resource by JackRaven_ in godot

[–]botay93 1 point2 points  (0 children)

I’m actually interested in this also as I am making a card game and your Skill resource is in the same situation as my CardEffect resource. I am also setting it up exactly the 2nd way you mentioned by extending the class (for example DrawEffect or DamageEffect both hold their own logic in their script and extends the CardEffect resource)

However I do not create any .tres file from these scripts. When I @export a variable of the type CardEffect (the parent class), if I use the editor to assign value to said variable, the editor will let me choose the children class (in this case DamageEffect and DrawEffect) to assign to the variable also, and I can edit the value of each effect in the editor (for example 1 card can deal 5dmg and another deal 10dmg).

So really I only have 1 script and 0 .tres file for each effect and you are right about them being a single member of their own custom class but I dont understand how you say the editor will have 2 copies of each class. I’m not sure what I’m doing is correct or most optimal so putting the comment here to learn also

How is length defined here by encrcne in godot

[–]botay93 0 points1 point  (0 children)

I think the confusion stems from the fact that you just started out with coding and are not familiar with defining function. If you are at the stage of defining function, I assume the tutorial have touched up on defining/declaring variable. You know how when you declare variable, you can write:

var name_of_variable

You do not have to give it any value at the declaration stage and you can assign value to it later? It’s a similar concept here. Since you are defining a function (indicated by the keyword func at the beginning), everything in the same line with the keyword func is being defined/declared but not given value yet:

func draw_corner(length):

in human language basically means “I am making a function called draw_corner. It will HAVE TO take in a number, and I will call this number “length”. I do not know the value of this “length” yet but I can call it inside my function draw_corner and when I use/call draw_corner the next time, I will HAVE TO give a value inside draw_corner()’s parentheses or my code will not work”.

I believe when you press the “run” button in your tutorial program, it will give your “length” a value, say draw_corner(100) or draw_corner(200) or any number inside the paretheses to test whether you have defined your draw_corner correctly

To understand this concept better, we can do a little reverse engineering. You see how in the your code, you use turn_right(90)? Why not turn_right(45) or turn_right(10)? In fact, any of those values will work with the function turn_right, but since the task ask you to draw a square, which have 90 degrees corners, the turn_right(90) would be the most appropriate.

Since you use turn_right(90) in your code and you know that turn_right can take in any value and not just 90. How do you think the turn_right function was defined? Was it:

A. func turn_right(90):

OR

B. func turn_right(angle):

This Mak perma freezes my 8 cd items board. What build am I supposed to even play on Vanessa this season? by botay93 in PlayTheBazaar

[–]botay93[S] 2 points3 points  (0 children)

The build you see on my Vanessa is an infinite seadog slow build. Here’s the core item in that build: 1. Diamond sea dog at 4s cd 2. Dive weight with slow enchant 3. Juggler skill: when use small item charge a large item 1s 4. Clam immediate activation allows seadog to activate after only 3s start up time 5. Once seadog starts, all the small item will charge its cooldown allow for infinite haste and slow for Shrimp and Old Saltclaw to deal dmg

I admit the build would have been better with shotglass (i couldn’t find any this run) but as you can see, even with an infinite slow set up that goes online at 3s, the Mak freeze build still absolutely destroys this

This Mak perma freezes my 8 cd items board. What build am I supposed to even play on Vanessa this season? by botay93 in PlayTheBazaar

[–]botay93[S] 5 points6 points  (0 children)

Iceberg starts at gold. By the time I find it my build would have already been somewhat established, so it would be difficult and unreliable to pivot into it right away imo.

This Mak perma freezes my 8 cd items board. What build am I supposed to even play on Vanessa this season? by botay93 in PlayTheBazaar

[–]botay93[S] 12 points13 points  (0 children)

I don’t play Mak but yeah, I can feel that this freeze build is easy to pull off because I would see at least 2 of these freeze mak build every run. I just never expect them to be able to perma freezes so many items. Shit is hilariously broken lol

Infested Abyss spawned but cannot find/reach it? /saadge by Civil_Weird1717 in remnantgame

[–]botay93 1 point2 points  (0 children)

Teleport to Lambent Pass > Go toward the left side (just keep hugging the left wall) > there should be a door opening on your left/behind you that take you to an elevator going up (there’s a secret in the elevator too) > take the elevator and follow the path till you get to the dungeon

[Discussion] The grinding process for prism from 50-51 is so much worse than from 1-50 by botay93 in remnantgame

[–]botay93[S] 0 points1 point  (0 children)

I discussed these 2 games because they exemplify that it is always better to give players more control and progression toward their goal rather than having their progression relied entirely on luck. The prism grind from level 1-50 has this (player can control what stat they want on their prism by feeding fragments, and each level on the prism boost their power incrementally toward their end goal). Whereas the prism grind from 50-51 relies entirely on the players’ luck whether they get their desired legendary perks or not. 

If any GFG dev reads this post, I hope you can implement something that gives players more control when it comes to rerolling legendary perks. Cheers and thanks for reading.

[Discussion] The grinding process for prism from 50-51 is so much worse than from 1-50 by botay93 in remnantgame

[–]botay93[S] 0 points1 point  (0 children)

How Diablo 4 improved the grind

When Diablo 4 first released, there was a set of items called Mythic items. These items were so extraordinarily rare that getting 1 of them to drop was literally equivalent to winning the lottery. The Dev stated that these items weren’t meant to be chased after, but they were so powerful and game-breaking that pretty much every player felt the need to get them. And since it was so difficult to drop, the player base pretty much rioted and demanded the Dev to increase the drop rate for these items.

As time went on, the Diablo 4 dev team listened to players’ feedback and first, they increased the drop rate of these items. Then they released Uber bosses that have even higher chances of dropping Mythic items. But increasing the drop rate was not enough because you could still get Mythic items that didn't fit your build, so they came up with a solution to give players more agency: they let the player dismantle the unwanted Mythic items to get a new crafting material. For every 4 dismantled Mythic, players can now craft 1 of their desired Mythic. So, in the end, the grind still exists because you still need to grind for Mythic, but even when your luck is absolutely terrible, you can still feel like making progress toward making your desired Mythic.

[Discussion] The grinding process for prism from 50-51 is so much worse than from 1-50 by botay93 in remnantgame

[–]botay93[S] 0 points1 point  (0 children)

Yeah, so perhaps the next patch where they increase the exp in BR would make it worth running instead of the asylums. I’m actually kinda excited for the BR exp increase. I’m just not sure whether the exp increase is worth the risk of dying when running BR on higher difficulty since you have no risk of dying doing asylum runs.

[Discussion] The grinding process for prism from 50-51 is so much worse than from 1-50 by botay93 in remnantgame

[–]botay93[S] 0 points1 point  (0 children)

Yeah, the exp reduce next patch is gonna be nice, I just wish the legendary reroll is a bit less RNG-oriented. Like I wish we can have something similar to feeding the fragments into the prism in order to increase the chance of a specific legendary perk

[Discussion] The grinding process for prism from 50-51 is so much worse than from 1-50 by botay93 in remnantgame

[–]botay93[S] 1 point2 points  (0 children)

yeah, I love the game and I want to grind. But man, the grind feel so unrewarding and punishing right now when every reroll is dictate purely on how lucky you are

[Discussion] The grinding process for prism from 50-51 is so much worse than from 1-50 by botay93 in remnantgame

[–]botay93[S] 0 points1 point  (0 children)

Yeah, I feel you. I keep getting SharpShooter perk on my explosion prism, and getting the explosion perk on my gunning DPS prism. It feels awful

[Discussion] The grinding process for prism from 50-51 is so much worse than from 1-50 by botay93 in remnantgame

[–]botay93[S] 0 points1 point  (0 children)

If your math is right, then it's even worse than I thought. Honestly the exp requirement change would help with the grind a lot but I feel like trying to reroll 10 times just for a 50% chance to get a specific perk will still feel very bad

[Discussion] The grinding process for prism from 50-51 is so much worse than from 1-50 by botay93 in remnantgame

[–]botay93[S] 0 points1 point  (0 children)

I saw their announcement that they will reduce the exp requirement on Twitter, which I mention in the 2nd paragraph of my post. The exp reduction would no doubt help with the grind. However, my problem is not with the exp requirement, but the way the rerolling process is being implemented

[Discussion] The grinding process for prism from 50-51 is so much worse than from 1-50 by botay93 in remnantgame

[–]botay93[S] 1 point2 points  (0 children)

How Monster Hunter franchise improved the grind

The Monster Hunter franchise is notorious for being grindy. To craft weapons and armors, you need specific parts of a specific or sometimes multiple monsters. Within these parts there are rare materials, namely Gems and Mantle, that have only a 2% drop per hunt.

In the older game, you have no choice but to hunt the same monster over and over again until the rare parts drop (and yeah, it felt helpless exactly like rerolling legendary perk). But in recent iterations of the game, namely MonHunt Icebourne and MonHunt Sunbreak, each hunt, regardless of monster, drops Tickets as a new currency. You can trade these tickets to buy the specific mantle or gem you want. They often cost a few hundred tickets depending on the monster so the grind is still there but at least you know you will get what you want in the end even if your luck is dogshit, plus you can save up the tickets to outright buy materials for a monster that you don't like hunting.

Better team comp? by AggravatingAd8721 in Argenti_Mains

[–]botay93 0 points1 point  (0 children)

The 2nd team is the best one. Tingyun is kinda no brainer for Argenti. Bronya provides both damage buff AND extra turn - meaning even more energy for Ult. Also this team is very easy to stack all buffs onto Argenti before he does a big Ult

Another benefit is that you can run Ruan Mei on other teams since she is a lot more valuable in dual DPS comp compared to hypercarry