Ardumon Mockup Image

That’s the gist of it.

Also I was thinking about how type bonus could be implemented last night, as I’m also trying add that in the project I’ve been working on. I was thinking of using an array along this line

int effectivenessMatrix[] = 
              f    w   e   f   water/flying    //target types
fire        { 1,  .5,  1,  1,  .5,
water         2,   1,  1,  1,   1,
electric      1,   2,  1,  2,   4,
flying        1,   1,  1,  1,   1 }
//^ attack types

And then using enums you could pull out the modifier:

enum types :  int {
  fire  //0
  water //1
  electric //2
  flying //3 
  water/flying //4

int getEffectivenessModifier( types attack, types target){    //water , fire
//(attack * total number of types ) * target
  index = ((static_cast<int>(attack) * 5 ) + static_cast<int>(target));  //((1 * 5 ) + 0 ) = 5
  return effectivenessMatrix[index];  // returns 2 for 2x damage.
}

This is also definitely better than how I had first planned it out in my project (forloops running through a list)

2 Likes

I learned Binary once, but I forgot it. I’ll use your link to refresh my memory while learning hex. Thankyou. :slight_smile:

True, it’s up to @Freezingsnail to decide that. Kryokali is also a really good name.

I saw that too when I was searching up salinkari. That’s a funny coincidence.

I guess it would be best to keep it simple then if it was able to be fitted.

Thankyou. I like the first one, but the third one’s a close second.

Haha, that’s hilarious. I gotta check that out.

True. I’ll keep that in mind.

3 Likes

Why not brainstorm with us, @LambKnight? The more, the merrier!

2 Likes

Pseudo code I’m guessing?
You can’t store .5 in an int (or at least not like that).

The general idea is close.
I’ll write something and post it when I’m done.

2 Likes

Yea I know you can’t have decimals, otherwise it wouldn’t be an integer. It could be -1 or something else, it really doesn’t matter what that numbers are since theres no damage formula to plug them in. Or you could just double all of the numbers and then have the modifier over 2 in the equation as a simple fix.

2 Likes
enum class Type : uint8_t
{
  None,
  Fire,
  Water,
  Electric,
  Wind,
};

constexpr const uint8_t TypeCount = 4;

class DualType
{
private:
	uint8_t value;

	constexpr const uint8_t Type1Mask = 0x0F;
	constexpr const uint8_t Type2Mask = 0x0F;
	constexpr const uint8_t Type1Shift = 0;
	constexpr const uint8_t Type2Shift = 4;

	constexpr uint8_t packTypes(Type type1, Type type2)
	{
		return ((static_cast<uint8_t>(type1) & Type1Mask) << Type1Shift) | ((static_cast<uint8_t>(type2) & Type2Mask) << Type2Shift);
	}
  
public:
	constexpr DualType(Type type) : value(packTypes(type, Type::None)) {}
	constexpr DualType(Type type1, Type type2) : value(packTypes(type1, type2)) {}
	
	constexpr Type getType1(void) const
	{
		return static_cast<Type>((this->value >> Type1Shift) & Type1Mask);
	}
	
	constexpr Type getType2(void) const
	{
		return static_cast<Type>((this->value >> Type2Shift) & Type2Mask);
	}
};

enum class Modifier : uint8_t
{
	Same,
	Half,
	Double,
	Quarter,
	Quadruple,
};

uint16_t applyModifier(uint16_t value, Modifier modifier)
{
	switch(modifier)
	{
		case Modifier::Same: return value;
		case Modifier::Half: return value >> 1;
		case Modifier::Double: return value << 1;
		case Modifier::Quarter: return value >> 2;
		case Modifier::Quadruple: return value << 2;
		default: return value;
	}
}

Modifier typeTable[TypeCount][TypeCount] PROGMEM =
{
	// Fire
	{
		Modifier::Half, // Fire
		Modifier::Quarter, // Water
		Modifier::Same, // Electric
		Modifier::Double, // Wind
	},
	// Water
	{
		Modifier::Double, // Fire
		Modifier::Same, // Water
		Modifier::Same, // Electric
		Modifier::Half, // Wind
	},
	// Electric
	{
		Modifier::Same, // Fire
		Modifier::Quadruple, // Water
		Modifier::Same, // Electric
		Modifier::Half, // Wind
	},
	// Wind
	{
		Modifier::Half, // Fire
		Modifier::Double, // Water
		Modifier::Same, // Electric
		Modifier::Half, // Wind
	},
};


Modifier getModifier(Type attackType, Type defendingType)
{
	return (attackType == Type::None || defendingType == Type::None)
	? Modifier::None :
	static_cast<Modifier>(pgm_read_byte(&typeTable[static_cast<uint8_t>(attackType)][static_cast<uint8_t>(defendingType)]));
}

uint16_t handleAttack(uint16_t baseValue, Type attackType, DualType defendingType)
{
	const Modifier mod1 = getModifier(attackType, defendingType.getType1());
	baseValue = applyModifier(baseValue, mod1);
	const Modifier mod2 = getModifier(attackType, defendingType.getType2());
	baseValue = applyModifier(baseValue, mod2);
	return baseValue;
}

This is a start at least.

2 Likes

The only thing I think I prefer is having the dual types just be their own thing like in my example since I didn’t want to use a 2d array. I guess it would depend on the total number of types and dual types though. If there’s 16 base types I see how your method would make more sense since there’s so many combinations it wouldn’t be practical to have 100s of enums. At the same time that would be necessary though assuming there’s only 30 monster, as at most you could only have 30 different combinations of types. Which still is a large amount. More realistically you could assume there would be at least 2 of each type for most cases which could lower that to an estimate of maybe 15-20 different type combinations.

Just as another note, you wouldn’t necessarily need the quad and quarter enums as the effective bonus is only 1, 2, or .5 which is stacked through multiplication. This is strictly cloning the mechanic though, and you have wind resisting electric so that’s clearly not your case in that example.

1 Like

Dual types don’t affect the need for a 2D array.
The 2D array comes about because you have an attacking type and a defending type.

If DualType wasn’t involved, the only difference would be that this:

uint16_t handleAttack(uint16_t baseValue, Type attackType, DualType defendingType)
{
	const Modifier mod1 = getModifier(attackType, defendingType.getType1());
	baseValue = applyModifier(baseValue, mod1);
	const Modifier mod2 = getModifier(attackType, defendingType.getType2());
	baseValue = applyModifier(baseValue, mod2);
	return baseValue;
}

Becomes this:

uint16_t handleAttack(uint16_t baseValue, Type attackType, Type defendingType)
{
	const Modifier mod = getModifier(attackType, defendingType);
	const uint16_t value = applyModifier(baseValue, mod);
	return value;
}

Your original table had a 4 in it, so I just assumed.

If there were only going to be x1, x2 and x0.5 then yes, that could be reduced.

This is before the main body of optimisation anyway, the small pool of modifiers would allow for more than one modifier per byte so that table could be crushed smaller anyway.

I just picked some random stuff for demonstration purposes.

I changed flying to wind to go closer to the classical elements rather than trying to be an outright clone.

2 Likes

The 4 was for the water/flying dual type, since it would be 2*2, but there’s no stacking in my method so you need the 4. Yours stacks and is also probably a lot closer to the actual funtion in the 'mon games.
Also I forgot the nullifying case now that I think about it that’s just immune -> x0

1 Like

More importantly the stacking approach doesn’t use as much memory.

One of the golden rules of memory saving is “don’t pre-calculate what you can calculate on the fly”, which is sort of the antithesis to the speed rule of “pre-calculate what’s costly to calculate”.

That’s easily added:

enum class Modifier : uint8_t
{
	Same,
	None,
	Half,
	Double,
	Quarter,
	Quadruple,
};

uint16_t applyModifier(uint16_t value, Modifier modifier)
{
	switch(modifier)
	{
		case Modifier::Same: return value;
		case Modifier::None: return 0;
		case Modifier::Half: return value >> 1;
		case Modifier::Double: return value << 1;
		case Modifier::Quarter: return value >> 2;
		case Modifier::Quadruple: return value << 2;
		default: return value;
	}
}
1 Like

I wondered instead of doing skills like in pokemon, there were just three move types like rock, paper, scissors. So depending on what you do versus what they do matters as well as typing. Rock would do bonus damage if they did scissors, but paper would do reduced damage versus scissors. The names should be changed, but that basic idea I think that might be kind of cool and would take less space to implement than skills.

I also really think being able to capture every monster without losing your team would be good for extending play time. The Nuzlock idea could be kept with it still.

3 Likes

When you think about it, type effectiveness is just a bunch of intersecting RPS triangles/ polygons. Would there still be individual types for the monsters in your idea? Or just the move types. The STAB bonus also plays a roll in modifying damage/ strategy. Perhaps only use the monster type for the STAB bonus and then use the two move types for the super effective/ resisted bonus?

Perhaps instead of a monster having a move table of x amount of moves and you can only choose 4 at a time, it would be better if they only had say up to 4 moves total, with them unlocking at certain levels. That way you would only need to store the monsters ID and level in EEPROM. I think that would be a good compromise to still keep some move variety and uniqueness between the monsters.

Say a 3 level evolution path, slug has one move. When it evolves at level 5 to snail it has 2 moves. At level 10 it evolves to iceSnail and has 3 moves. At lvl 15 it learns its 4th move.

Struct move {
  int attackPower;
  type attacktype;
  int levelRequirement;
}
move basicRock = {10, rock, 0}
move superRock = {20, rock, 15)

Also Nuzlock is a self imposed rule set so as long as you have a method of removing monsters from your party the rules could be adapted regardless of what other changes are made.

1 Like

I’d say it wouldn’t be a bad idea to include nuzlock. It’d make the player more engaged rather than them merely mashing the A button, and it’d give them a sense of urgency and difficulty when in a tough battle, and a high sense of acomplishment or failure, depending whether they won or lost and if they lost any good monsters in the battle. Yeah, they can implement it themselves, but what’s not to say that they won’t go back on their own rules? Those are just my two cents.

also, not to pressure you but, what are you going to name your snail Mon?

I figured the moves effectiveness could be in addition to typing of the monsters. My only concern would be getting the battle and progression system small enough to fit on the Arduboy, but if you can pull it off that would definitely be ideal :grin:

1 Like

This thread is a really good. It is like a collaborative project taking off. How would something like this be done that way? Just forking off the git hub? A lot of what I do professionally is Project Management. So just curious how it is done from a software development point of view.

2 Likes

Nuzlock is a huge pain to play though, and it definitely requires a better understanding of the game mechanics to complete. The original nuzlock run failed at the champion battle. + the additional rulesets would be costly. The premis is you can add additional restriction through pick and choose depending on how you would like to play. I think that’s best left as self imposed rules.

I don’t really care about the name, how about IceCargo? Your suggestions are all good. My favorite name is the german name for koffing, Smogon.

This is why I suggested relying on separate files. You could split up the over world into different parts to make room for the battle engine. I don’t think progression would be too costly. The original had a couple hooks for progression. HM’s/items, gym badges, and story elements. All three of those tied in together to determine when you got hm’s and when you could use them. So its really just 1 condition to progress if you simplify it.
Stats are seeded from a base seed and then calculated on the fly using the level and and dv/ev/iv modifiers. In this case just level could be used. So progressing the monsters through levels is more about balancing that equation and basestats to feel good than designing a leveling system. All you need is a exp tracking variable, an equation to calculate the stat, and an equation to determine if they hit the level up required exp.

Also no one guessed so the crab is suppose to be a spin off of @filmote’s space invader avatar.

1 Like

@Freezingsnail the overworld really doesn’t take much space, splitting up mechanics to different sketches could save space, but at the cost of the player being tied to a computer constantly interrupting gameplay for uploading. The Arduboy is convenient to carry around and play wherever, I don’t think splitting it up would be worth it.

@fredster I don’t know if anyone has officially said if they’ll take on the role of coding it. It will certainly take a talented coder. But once coding starts a GitHub would probably be the way to go as well as something like slack for members to communicate. I might be able to assist with the overworld if development on the game starts.

1 Like

Good point. Most people would probably be playing casually, now that I think of about it. Yeah, it’s probably for the best self imposed.

I like the name Icecargo. It also can be called Icargo.

I never would of guessed that. :smile:

That would probably be mandatory anyway.

Hrm, I think that might be a bit limiting.
Though Yokai Watch sort of gets away with it, but in that you don’t actually control the monster’s actions exactly and frankly I don’t like their battle mechanics as much as Pokemon.

Storing the moves in EEPROM wouldn’t be too costly, you could either store a move ID, which would probably be 1 byte since there would almost certainly be less than 255 moves, so that’s only 4 bytes per monster, or you could store an index into the monster’s move pool, and if we keep the pools small then that could be squashed into 2 or 3 bytes.

Another possibility is to have some moves essentially function the same but taking on the primary or secondary type of the monster using it, so effectively there’s only one move in memory but it ends up being several moves in practice.

I don’t think nuzlocke should be enforced.
There are plenty of people who don’t like the nuzlocke rules, it’s better to allow people who like them to choose to use them than to enforce them on people who don’t want them.
Some people only play casually and it would be better to allow them to do so.

This is a good point.
I can imagine a game where people spend several days reaching the final battle and then lose all their progress would soon be abandonned by all but the obsessives.

I agree.

It depends how organised the team is.
Sometimes projects done in free time are very haphazard.

Ideally all work is done in github branches or forks and then merged into the main code via PR, but that doesn’t always pan out, especially on smaller teams.

It would be Icecargot to match up with Escargot.
I think people would appreaciate the obviousness of the pun.

I think it would need to be a little bit more than that.
If you couldn’t somehow influence progression then everyone’s monsters would be exactly the same at the same level.
Either that or everything would be oriented on the IVs (if there were any).

I’d rather do away with IVs than EVs since there probably wouldn’t be a breeding mechanic and it would cut out the tedium of trying to get a good set of IVs.

Also remember that base stats don’t have to be saved to EEPROM, they’d probably be defined in the equivalent of the Pokedex, in progmem.

I’ll be frank, I’d have to squint to see the resemblence.

As a crab creature it makes sense, as a variation of @filmote’s space invader it’s a bit of a stretch.

It depends. If we can fit more monsters in by splitting the world up then it may be worth doing, especially if the maps were built in such a way that they last a long time.

In fact, perhaps the maps could be different zones that are playable in any order, and the level of the monsters in the field is tied either to the number of maps the player has cleared or the level of the monsters in their party.

That way people could choose which order to tackle the maps in, making it more interesting for players (kind of like a choose your own adventure thing - you choose the order you clear the maps in) and giving a bit of replayability.


While I think of it, I think we could reduce the stat pool down to just hp, strength, resistance and speed and forgo the physical/special stat split.

1 Like

I didn’t mean to Imply that. I was thinking of the case of having to store 30 monsters in the pc and 4 values for the moves + the level value. that would be 60-120 bytes for all the stored moves.

That was more of a joke referencing Magcargo.

I don’t think this is the worst compromise since team building is equally as important. iv/dv values are awful. They don’t really make the monsters different, just worse than ones with the max values.

As for that sprite, I didn’t want to copy the alien that much so I only really used the basic shape. The eye stalks are suppose to be the antennae ect. Like I said i’m not the best at sprites. :coffin:

All that’s missing is the special stat when comparing to gen 1. In this scope though I agree special/physical split might not be worth implementing. That’s something that would need play testing to determine though.

also,

The original thread was brutal to say the least. I’ve never gotten past the first badge personally.

1 Like