Saplings-Projects / 1M_sub

Game project for Fauna's 1M sub : a dungeon crawler
GNU General Public License v3.0
2 stars 12 forks source link

Select a group of enemy when entering a combat depending on map position #128

Open Turtyo opened 3 weeks ago

Turtyo commented 3 weeks ago

Feature Description

We need to be able to select enemies for certain areas of the game, and to load some of their information (such as their sprite for example).

Motivation

We currently only have two enemies in the game, which are the same for all combats, we need to have more for the game.

Acceptance Criteria

Proposed Solution

Make an enum with each enemy type inside global enums (we won't do it with strings, because it's always error prone).

We need some sort of table that lists possible group of enemies by level of the map. A simple solution would be a dictionary where a key is a certain group of enemy (represented as an array of enemies). The values could be which levels of the map we allow this group of enemy to appear on. We might need a separate dictionary for mini-boss and bosses.

A question is "how do we represent the levels of the map ? We could do it in %, but it was already mentioned inside #79 to use bitmasks to code different parts of the tree, but since it is not implemented yet, the choice is still up in the air. Using % would allow it to be adaptable depending on the size of the map, as well as being easy to change if we want to change the range in which we want the group of enemy.

For example, we could have a lower bound and an upper bound %, and we can just change those if we want the group of enemy to be available in different parts of the map. We also need to say in which floor is a certain enemy available. I think a certain enemy should have fixed HP and capabilities, meaning we don't change those depending on the level inside the tree (as that would be hard for balancing later on).

We might need a new class for coding the part of the maps, or we can just make an array of values; an enemy available between 40 and 60% of the 3rd floor would be [3, 40, 60] for example. When going to check which enemy group to spawn, we go into this dictionary and check which groups are in the correct range. If we make a class, we can re-use it for other things, which is why I prefer this approach.

Another question to take into account would be if we allow re-using the same group of enemy multiple times, or if we add a boolean to say if we used this group of enemy already.

Additional Context

This needs to be done before #127 because loading enemy decks needs to have enemies loaded. We have to create a new enemy scene for each enemy to change their sprite based on their name.

Lann-hyl commented 3 weeks ago

For the table, I'd maybe flip the keys and values, the keys are the levels and values are the group of enemies, so that depending on the level you directly pick at random from the array of enemies. It also allows reusing enemies pretty easily.

Turtyo commented 3 weeks ago

if we do it this way, it means the values are an array of possible enemy groups ? the structure would be:

{
[tree_level, lower_percent, higher_percent] : [enemy_group_1, enemy_group_2, enemy_group_3],
[tree_level_2, another_lower_percent, another_higher_percent]: [...]
}

something like that ? the advantage of doing it the other way is to be able to change the values for a certain group of enemies and I'm assuming in the (level: enemy) representation, the group of enemy is on no two arrays are the same time. Which means there is really a segmentation of tree levels (like 0-30, 30-60 and 60-100)

whereas if we do it with (enemy: level), we can have an enemy group be 0-30 and another be 10-40 for example.

Honestly either solution work, but I'm not sure of what would be the best to manipulate

Turtyo commented 3 weeks ago

I'm also wondering if i should create an actual enemy_group class or if we stay on array of enemies ? If we create a class, we could also include information other the the enemies. For example, the relative positioning of each enemy sprite so that they don't collide with one another on screen

Lann-hyl commented 3 weeks ago

I also agree with enemies having fixed hp, it is kind of the same in Dicey Dungeons and it is easier to manage on our side

also for terminology, what do you mean by floor? Is it the different segmentation of the tree (so floor 1 is 0-30, 2 is 30-60, etc...)

We could have more segmentation (like first and second half of floors), and allow enemies to appear in multiple segmentations (for example second half of floor 1 and first half of floor 2) Maybe it's not easier to use, but I feel like it could be less confusing (need to see)

For the table, I'd put in individual enemies or if you want groups, we can put the levels (as in exp, not 'map level') of the enemies that can spawn like in dicey dungeons https://diceydungeons.fandom.com/wiki/Enemies, with each enemy having a fixed level

Turtyo commented 3 weeks ago

Yes let's agree on the vocabulary, by floor I meant a tree section (so floor is one generation of the map), but "section" might be more appropriate. So 3 sections. And each section is from 0 to 100% of that section, so if each section is 10 levels, you 10%-30% of section 1 is from floor 1 to floor 3, 0-40% of section 3 is from the 0th level to the 4th level of section 3.

I would rather craft group of enemies instead of specifying just for each enemy. Because some enemies might be easy to deal with with another enemy, but might be harder with a third type. Like for example you have two DPS enemy which are easy to deal with (so you could say you can put them between 20%-50% of section 2), but you make that same DPS enemy with a tank, and suddenly it becomes a harder fight than the two DPS.

It will be easier for balancing to craft group of enemies. It will also be easier for positioning purpose (on the screen, depending on their size). In dicey dungeon, isn't it one enemy per combat ?

Lann-hyl commented 3 weeks ago

So you want to make fixed groups, so some enemies only spawn together, and some only alone for example? I'm not sure to understand what you mean by 'group' (like sets of 2/3 enemies that is fixed?). If so that'd be time consuming, but still works with both (level: mob) and (mob: level) tables

For sprites I haven't seen them yet so that need to be tested yes

Yes Dicey dungeons has only one enemy per combat, and has floors as well. Each floor has a fixed number of enemies and their level (floor 1 is two enemies level 1, floor 2 is three enemies level 2, floor 3 is one enemy level 2 and two level 3, etc). But the enemy itself is picked from the pool of enemy level, so it is quite different from our game

Turtyo commented 3 weeks ago

Yes, I want to make fixed groups (because, also easier for balancing encounters later). If you think of StS for example, it's done this way. And yes it works for both (level: mob) and (mob: level) tables. By group I mean a set of enemies, like 1 to 4 enemies I think. It would be a bit time consuming to make the groups, but it would be less time consuming later to balance it. Plus we can make some interesting combo, so it's probably more interesting for the player too

Lann-hyl commented 2 weeks ago

For the rest i'm all good

Turtyo commented 2 weeks ago

I think the (level: enemy) is better in the end, we'll have to make the separation smooth. Plus it'll be easier to make sure we have enough enemy groups for each separation (if we don't do repeats that is). To get the tree section we are in, use a simple number from 1 to 3; so the key is (X, Y, Z) with X the tree section, Y the lower percent and Z the higher percent where the enemy can appear.

I'm assuming in this idea, we make each division separate right ? Like you can't have (1, 10, 30) and (1, 20, 40) but you do (1,10, 30) and (1, 30, 50) ? Also, lower bound included and higher bound excluded seems like the logical thing to do (as that's what most range functions do).

It's true that it would be better if we don't have to hardcode enemy positions. We can do left is behind and right is in front, so if you have a list of enemies, first one is left, next one is spawned more right and in front, etc...

Lann-hyl commented 2 weeks ago

Yeah separate is better, otherwise it doesn't make sense to use (level:enemy). Just need to make sure that the higher percent/bound of a previous area of a certain map is the lower percent/bound of the next area

Lann-hyl commented 2 weeks ago

And for repeats on enemy groups, you can do something like a queue, the same idea as #79 where we shuffle the possibilities, go over them, then if we need those again, we do another shuffle of the possibilities so basically you ensure you pick everything once before starting to pick one twice

you could also have repeat mobs in different enemy groups and that would be two separate encounters

Turtyo commented 2 weeks ago

Alright, all good for me :+1:

I'll put enemies even if we don't have their sprite and use a default image for those; I'll add a boolean in the debug file, the enemies without a proper sprite will only be used if this boolean is true. This will prevent a default mob from getting into a release