mirror of https://gitlab.com/drummyfish/anarch.git
Add monster table
This commit is contained in:
parent
b4ceb1603b
commit
8745a04952
54
constants.h
54
constants.h
|
@ -267,6 +267,56 @@
|
||||||
#define SFG_HUD_BAR_HEIGHT \
|
#define SFG_HUD_BAR_HEIGHT \
|
||||||
(SFG_FONT_CHARACTER_SIZE * SFG_FONT_SIZE_MEDIUM + SFG_HUD_MARGIN * 2 + 1)
|
(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
|
// weapons and projectiles
|
||||||
|
|
||||||
|
@ -296,7 +346,7 @@
|
||||||
/**
|
/**
|
||||||
Table of weapon attributes, each as a byte in format:
|
Table of weapon attributes, each as a byte in format:
|
||||||
|
|
||||||
cccccfff
|
MSB cccccfff LSB
|
||||||
|
|
||||||
fff: fire type
|
fff: fire type
|
||||||
ccccc: fire cooldown in frames, i.e. time after which the next shot can be
|
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:
|
Table of projectile attributes, each as a byte in format:
|
||||||
|
|
||||||
lllllsss
|
MSB lllllsss LSB
|
||||||
|
|
||||||
fff: half speed in game squares per second
|
fff: half speed in game squares per second
|
||||||
lllll: eigth of frames to live
|
lllll: eigth of frames to live
|
||||||
|
|
5
levels.h
5
levels.h
|
@ -102,6 +102,11 @@ typedef struct
|
||||||
#define SFG_LEVEL_ELEMENT_MONSTER_TURRET 0x50
|
#define SFG_LEVEL_ELEMENT_MONSTER_TURRET 0x50
|
||||||
#define SFG_LEVEL_ELEMENT_MONSTER_EXPLODER 0x60
|
#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)
|
#define SFG_LEVEL_ELEMENT_TYPE_IS_MOSTER(t) (((t) & 0x0f) == 0)
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
|
124
main.c
124
main.c
|
@ -947,7 +947,8 @@ void SFG_setAndInitLevel(const SFG_Level *level)
|
||||||
&(SFG_currentLevel.monsterRecords[SFG_currentLevel.monsterRecordCount]);
|
&(SFG_currentLevel.monsterRecords[SFG_currentLevel.monsterRecordCount]);
|
||||||
|
|
||||||
monster->stateType = e->type | 0;
|
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[0] = e->coords[0] * 4;
|
||||||
monster->coords[1] = e->coords[1] * 4;
|
monster->coords[1] = e->coords[1] * 4;
|
||||||
|
|
||||||
|
@ -992,7 +993,7 @@ void SFG_init()
|
||||||
|
|
||||||
SFG_backgroundScroll = 0;
|
SFG_backgroundScroll = 0;
|
||||||
|
|
||||||
SFG_setAndInitLevel(&SFG_level1);
|
SFG_setAndInitLevel(&SFG_level0);
|
||||||
|
|
||||||
SFG_lastFrameTimeMs = SFG_getTimeMs();
|
SFG_lastFrameTimeMs = SFG_getTimeMs();
|
||||||
}
|
}
|
||||||
|
@ -1034,6 +1035,9 @@ uint8_t SFG_launchProjectile(
|
||||||
RCL_Unit offsetDistance
|
RCL_Unit offsetDistance
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
if (type == SFG_PROJECTILE_NONE)
|
||||||
|
return;
|
||||||
|
|
||||||
SFG_ProjectileRecord p;
|
SFG_ProjectileRecord p;
|
||||||
|
|
||||||
p.type = type;
|
p.type = type;
|
||||||
|
@ -1249,20 +1253,25 @@ void SFG_monsterPerformAI(SFG_MonsterRecord *monster)
|
||||||
{
|
{
|
||||||
uint8_t state = SFG_MR_STATE(*monster);
|
uint8_t state = SFG_MR_STATE(*monster);
|
||||||
uint8_t type = SFG_MR_TYPE(*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];
|
int8_t coordAdd[2];
|
||||||
|
|
||||||
coordAdd[0] = 0;
|
coordAdd[0] = 0;
|
||||||
coordAdd[1] = 0;
|
coordAdd[1] = 0;
|
||||||
|
|
||||||
uint8_t melee = (type == SFG_LEVEL_ELEMENT_MONSTER_WARRIOR) ||
|
uint8_t notRanged =
|
||||||
(type == SFG_LEVEL_ELEMENT_MONSTER_EXPLODER);
|
(attackType == SFG_MONSTER_ATTACK_MELEE) ||
|
||||||
|
(attackType == SFG_MONSTER_ATTACK_EXPLODE);
|
||||||
|
|
||||||
if ( // sometimes randomly change state
|
if ( // sometimes randomly attack
|
||||||
(SFG_random() < SFG_AI_RANDOM_CHANGE_PROBABILITY) &&
|
!notRanged &&
|
||||||
(type != SFG_LEVEL_ELEMENT_MONSTER_EXPLODER))
|
(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
|
// attack
|
||||||
|
|
||||||
|
@ -1281,9 +1290,35 @@ void SFG_monsterPerformAI(SFG_MonsterRecord *monster)
|
||||||
|
|
||||||
dir = RCL_normalize(dir);
|
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(
|
SFG_launchProjectile(
|
||||||
type != SFG_LEVEL_ELEMENT_MONSTER_PLASMABOT ?
|
projectile,
|
||||||
SFG_PROJECTILE_FIREBALL : SFG_PROJECTILE_PLASMA,
|
|
||||||
pos,
|
pos,
|
||||||
SFG_floorHeightAt(
|
SFG_floorHeightAt(
|
||||||
SFG_MONSTER_COORD_TO_SQUARES(monster->coords[0]),
|
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)
|
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 mX = SFG_MONSTER_COORD_TO_SQUARES(monster->coords[0]);
|
||||||
uint8_t mY = SFG_MONSTER_COORD_TO_SQUARES(monster->coords[1]);
|
uint8_t mY = SFG_MONSTER_COORD_TO_SQUARES(monster->coords[1]);
|
||||||
|
|
||||||
if (!( // exploder will explode when close
|
uint8_t isClose = // close to player?
|
||||||
(type == SFG_LEVEL_ELEMENT_MONSTER_EXPLODER) &&
|
(
|
||||||
(((mX > SFG_player.squarePosition[0]) ?
|
(
|
||||||
(mX - SFG_player.squarePosition[0]) :
|
(mX > SFG_player.squarePosition[0]) ?
|
||||||
(SFG_player.squarePosition[0] - mX)) <= 1) &&
|
(mX - SFG_player.squarePosition[0]) :
|
||||||
(((mY > SFG_player.squarePosition[1]) ?
|
(SFG_player.squarePosition[0] - mX)
|
||||||
(mY - SFG_player.squarePosition[1]) :
|
) <= 1
|
||||||
(SFG_player.squarePosition[1] - mY)) <= 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 (mX > SFG_player.squarePosition[0])
|
||||||
{
|
{
|
||||||
if (mY > SFG_player.squarePosition[1])
|
if (mY > SFG_player.squarePosition[1])
|
||||||
|
@ -1345,22 +1390,32 @@ void SFG_monsterPerformAI(SFG_MonsterRecord *monster)
|
||||||
}
|
}
|
||||||
else
|
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 =
|
uint8_t properties;
|
||||||
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;
|
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)
|
switch (SFG_random() % 8)
|
||||||
{
|
{
|
||||||
|
@ -1382,7 +1437,12 @@ void SFG_monsterPerformAI(SFG_MonsterRecord *monster)
|
||||||
}
|
}
|
||||||
else
|
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 ||
|
if (state == SFG_MONSTER_STATE_GOING_E ||
|
||||||
state == SFG_MONSTER_STATE_GOING_NE ||
|
state == SFG_MONSTER_STATE_GOING_NE ||
|
||||||
|
|
Loading…
Reference in New Issue