From 8745a04952be8847dd4193b9ba8fa4445b0c8562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Tue, 31 Dec 2019 00:35:35 +0100 Subject: [PATCH] Add monster table --- constants.h | 54 ++++++++++++++++++++++- levels.h | 5 +++ main.c | 124 ++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 149 insertions(+), 34 deletions(-) diff --git a/constants.h b/constants.h index 9b9d320..71f5c7d 100644 --- a/constants.h +++ b/constants.h @@ -267,6 +267,56 @@ #define SFG_HUD_BAR_HEIGHT \ (SFG_FONT_CHARACTER_SIZE * SFG_FONT_SIZE_MEDIUM + SFG_HUD_MARGIN * 2 + 1) +// ---------------------------- +// monsters + +#define SFG_MONSTER_ATTACK_MELEE 0 +#define SFG_MONSTER_ATTACK_FIREBALL 1 +#define SFG_MONSTER_ATTACK_BULLET 2 +#define SFG_MONSTER_ATTACK_FIREBALL_BULLET 3 +#define SFG_MONSTER_ATTACK_PLASMA 4 +#define SFG_MONSTER_ATTACK_EXPLODE 5 + +#define SFG_MONSTER_ATTRIBUTE(attackType,aggressivity0to255,health0to255,spriteSize0to3) \ + ((uint16_t) ( \ + attackType | \ + ((aggressivity0to255 / 8) << 3) | \ + (spriteSize0to3 << 8) | \ + ((health0to255 / 4) << 10))) + +#define SFG_GET_MONSTER_ATTACK_TYPE(monsterNumber) \ + (SFG_monsterAttributeTable[monsterNumber] & 0x0007) + +#define SFG_GET_MONSTER_AGGRESSIVITY(monsterNumber) \ + (((SFG_monsterAttributeTable[monsterNumber] >> 3) & 0x1F) * 8) + +#define SFG_GET_MONSTER_SPRITE_SIZE(monsterNumber) \ + ((SFG_monsterAttributeTable[monsterNumber] >> 8) & 0x03) + +#define SFG_GET_MONSTER_MAX_HEALTH(monsterNumber) \ + (((SFG_monsterAttributeTable[monsterNumber] >> 10) & 0x3F) * 4) + +/** + Table of monster attributes, each as a 16bit word in format: + + MSB hhhhhhssaaaattt LSB + + ttt: attack type + aaaaa: aggressivity (frequence of attacks), 0 to 31 + ss: sprite size + hhhhhh: health, 0 to 63 +*/ +uint16_t SFG_monsterAttributeTable[SFG_MONSTERS_TOTAL] = +{ + /* spider */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_FIREBALL,40,120,3), + /* destr. */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_FIREBALL_BULLET,50,130,3), + /* warrior */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_MELEE,255,70,2), + /* plasma */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_PLASMA,55,92,2), + /* ender */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_FIREBALL_BULLET,75,255,4), + /* turret */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_BULLET,32,50,2), + /* explod. */ SFG_MONSTER_ATTRIBUTE(SFG_MONSTER_ATTACK_EXPLODE,255,60,2) +}; + // ---------------------------- // weapons and projectiles @@ -296,7 +346,7 @@ /** Table of weapon attributes, each as a byte in format: - cccccfff + MSB cccccfff LSB fff: fire type ccccc: fire cooldown in frames, i.e. time after which the next shot can be @@ -334,7 +384,7 @@ SFG_PROGRAM_MEMORY uint8_t SFG_weaponAttributeTable[SFG_WEAPONS_TOTAL] = /** Table of projectile attributes, each as a byte in format: - lllllsss + MSB lllllsss LSB fff: half speed in game squares per second lllll: eigth of frames to live diff --git a/levels.h b/levels.h index 343d736..a6216df 100644 --- a/levels.h +++ b/levels.h @@ -102,6 +102,11 @@ typedef struct #define SFG_LEVEL_ELEMENT_MONSTER_TURRET 0x50 #define SFG_LEVEL_ELEMENT_MONSTER_EXPLODER 0x60 +#define SFG_MONSTERS_TOTAL 7 + +#define SFG_MONSTER_TYPE_TO_INDEX(monsterType) \ + ((monsterType) >> 4) + #define SFG_LEVEL_ELEMENT_TYPE_IS_MOSTER(t) (((t) & 0x0f) == 0) typedef struct diff --git a/main.c b/main.c index 448b787..a635ecf 100755 --- a/main.c +++ b/main.c @@ -947,7 +947,8 @@ void SFG_setAndInitLevel(const SFG_Level *level) &(SFG_currentLevel.monsterRecords[SFG_currentLevel.monsterRecordCount]); monster->stateType = e->type | 0; - monster->health = 100; + monster->health = SFG_GET_MONSTER_MAX_HEALTH(SFG_MONSTER_TYPE_TO_INDEX(e->type)); + monster->coords[0] = e->coords[0] * 4; monster->coords[1] = e->coords[1] * 4; @@ -992,7 +993,7 @@ void SFG_init() SFG_backgroundScroll = 0; - SFG_setAndInitLevel(&SFG_level1); + SFG_setAndInitLevel(&SFG_level0); SFG_lastFrameTimeMs = SFG_getTimeMs(); } @@ -1034,6 +1035,9 @@ uint8_t SFG_launchProjectile( RCL_Unit offsetDistance ) { + if (type == SFG_PROJECTILE_NONE) + return; + SFG_ProjectileRecord p; p.type = type; @@ -1249,20 +1253,25 @@ void SFG_monsterPerformAI(SFG_MonsterRecord *monster) { uint8_t state = SFG_MR_STATE(*monster); uint8_t type = SFG_MR_TYPE(*monster); + uint8_t monsterNumber = SFG_MONSTER_TYPE_TO_INDEX(type); + uint8_t attackType = SFG_GET_MONSTER_ATTACK_TYPE(monsterNumber); int8_t coordAdd[2]; coordAdd[0] = 0; coordAdd[1] = 0; - uint8_t melee = (type == SFG_LEVEL_ELEMENT_MONSTER_WARRIOR) || - (type == SFG_LEVEL_ELEMENT_MONSTER_EXPLODER); + uint8_t notRanged = + (attackType == SFG_MONSTER_ATTACK_MELEE) || + (attackType == SFG_MONSTER_ATTACK_EXPLODE); - if ( // sometimes randomly change state - (SFG_random() < SFG_AI_RANDOM_CHANGE_PROBABILITY) && - (type != SFG_LEVEL_ELEMENT_MONSTER_EXPLODER)) + if ( // sometimes randomly attack + !notRanged && + (SFG_random() < + SFG_GET_MONSTER_AGGRESSIVITY(SFG_MONSTER_TYPE_TO_INDEX(type))) + ) { - if (!melee && (SFG_random() % 4 != 0)) + if (!notRanged && (SFG_random() % 4 != 0)) { // attack @@ -1281,9 +1290,35 @@ void SFG_monsterPerformAI(SFG_MonsterRecord *monster) dir = RCL_normalize(dir); + uint8_t projectile; + + switch (SFG_GET_MONSTER_ATTACK_TYPE(monsterNumber)) + { + case SFG_MONSTER_ATTACK_FIREBALL: + projectile = SFG_PROJECTILE_FIREBALL; + break; + + case SFG_MONSTER_ATTACK_BULLET: + projectile = SFG_PROJECTILE_BULLET; + break; + + case SFG_MONSTER_ATTACK_PLASMA: + projectile = SFG_PROJECTILE_PLASMA; + break; + + case SFG_MONSTER_ATTACK_FIREBALL_BULLET: + projectile = (SFG_random() < 128) ? + SFG_PROJECTILE_FIREBALL : + SFG_PROJECTILE_BULLET; + break; + + default: + projectile = SFG_PROJECTILE_NONE; + break; + } + SFG_launchProjectile( - type != SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT ? - SFG_PROJECTILE_FIREBALL : SFG_PROJECTILE_PLASMA, + projectile, pos, SFG_floorHeightAt( SFG_MONSTER_COORD_TO_SQUARES(monster->coords[0]), @@ -1300,23 +1335,33 @@ void SFG_monsterPerformAI(SFG_MonsterRecord *monster) } else if (state == SFG_MONSTER_STATE_IDLE) { - if (melee) + if (notRanged) { - // melee monsters walk towards player + // non-ranged monsters walk towards player uint8_t mX = SFG_MONSTER_COORD_TO_SQUARES(monster->coords[0]); uint8_t mY = SFG_MONSTER_COORD_TO_SQUARES(monster->coords[1]); - if (!( // exploder will explode when close - (type == SFG_LEVEL_ELEMENT_MONSTER_EXPLODER) && - (((mX > SFG_player.squarePosition[0]) ? - (mX - SFG_player.squarePosition[0]) : - (SFG_player.squarePosition[0] - mX)) <= 1) && - (((mY > SFG_player.squarePosition[1]) ? - (mY - SFG_player.squarePosition[1]) : - (SFG_player.squarePosition[1] - mY)) <= 1) - )) + uint8_t isClose = // close to player? + ( + ( + (mX > SFG_player.squarePosition[0]) ? + (mX - SFG_player.squarePosition[0]) : + (SFG_player.squarePosition[0] - mX) + ) <= 1 + ) && + ( + ( + (mY > SFG_player.squarePosition[1]) ? + (mY - SFG_player.squarePosition[1]) : + (SFG_player.squarePosition[1] - mY) + ) <= 1 + ); + + if (!isClose) { + // walk towards player + if (mX > SFG_player.squarePosition[0]) { if (mY > SFG_player.squarePosition[1]) @@ -1345,22 +1390,32 @@ void SFG_monsterPerformAI(SFG_MonsterRecord *monster) } else { - // exploder explodes + if (attackType == SFG_MONSTER_ATTACK_MELEE) + { + // melee attack - uint8_t properties; + state = SFG_MONSTER_STATE_ATTACKING; + } + else // SFG_MONSTER_ATTACK_EXPLODE + { + // explode - SFG_TileDefinition tile = - SFG_getMapTile(SFG_currentLevel.levelPointer,mX,mY,&properties); - - SFG_createExplosion(mX * RCL_UNITS_PER_SQUARE ,mY * RCL_UNITS_PER_SQUARE, - SFG_TILE_FLOOR_HEIGHT(tile) * SFG_WALL_HEIGHT_STEP + SFG_WALL_HEIGHT_STEP); + uint8_t properties; - monster->health = 0; + SFG_TileDefinition tile = + SFG_getMapTile(SFG_currentLevel.levelPointer,mX,mY,&properties); + + SFG_createExplosion(mX * RCL_UNITS_PER_SQUARE ,mY * RCL_UNITS_PER_SQUARE, + SFG_TILE_FLOOR_HEIGHT(tile) * SFG_WALL_HEIGHT_STEP + SFG_WALL_HEIGHT_STEP); + + monster->health = 0; + + } } } - else + else // ranged monsters { - // ranged monsters choose direction randomly + // choose walk direction randomly switch (SFG_random() % 8) { @@ -1382,7 +1437,12 @@ void SFG_monsterPerformAI(SFG_MonsterRecord *monster) } else { - int8_t add = type != SFG_LEVEL_ELEMENT_MONSTER_EXPLODER ? 1 : 3; + int8_t add = 1; + + if (attackType == SFG_MONSTER_ATTACK_MELEE) + add = 2; + else if (attackType == SFG_MONSTER_ATTACK_EXPLODE) + add = 3; if (state == SFG_MONSTER_STATE_GOING_E || state == SFG_MONSTER_STATE_GOING_NE ||