Add monster table

This commit is contained in:
Miloslav Číž 2019-12-31 00:35:35 +01:00
parent b4ceb1603b
commit 8745a04952
3 changed files with 149 additions and 34 deletions

View File

@ -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

View File

@ -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

124
main.c
View File

@ -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 ||