From a51aeec38ebd773dc6f1844842af646a44e555c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 2 Jan 2020 19:40:00 +0100 Subject: [PATCH] Add player melee --- constants.h | 15 +++++-- main.c | 111 ++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 94 insertions(+), 32 deletions(-) diff --git a/constants.h b/constants.h index 2b7eee9..c623670 100644 --- a/constants.h +++ b/constants.h @@ -29,15 +29,24 @@ /** Gravity acceleration in squares / (second^2). */ - #define SFG_GRAVITY_ACCELERATION 30 /** Initial upwards speed of player's jump, in squares per second. */ - #define SFG_PLAYER_JUMP_SPEED 80 +/** + Melee and close-up attack range, in RCL_Units. +*/ +#define SFG_MELEE_RANGE 1400 + +/** + Player's melee hit range, in RCL_Units (RCL_UNITS_PER_SQUARE means full angle, + 180 degrees to both sides). +*/ +#define SFG_PLAYER_MELEE_ANGLE 512 + /** How quickly elevators and squeezers move, in RCL_Unit per second. */ @@ -380,7 +389,7 @@ SFG_PROGRAM_MEMORY uint8_t SFG_weaponAttributeTable[SFG_WEAPONS_TOTAL] = SFG_PROGRAM_MEMORY uint8_t SFG_attackDamageTable[SFG_WEAPON_FIRE_TYPES_TOTAL] = { - /* melee */ 8, + /* melee */ 7, /* bullet */ 10, /* explostion (fireball) */ 13, /* plasma */ 17 diff --git a/main.c b/main.c index 83ea995..9a5d194 100755 --- a/main.c +++ b/main.c @@ -328,9 +328,6 @@ uint8_t SFG_getDamageValue(uint8_t attackType) return 0; int32_t value = SFG_attackDamageTable[attackType]; // has to be signed - -printf("%d ",value); - int32_t maxAdd = (value * SFG_DAMAGE_RANDOMNESS) / 256; value = value - (maxAdd / 2) + (SFG_random() * maxAdd / 256); @@ -338,7 +335,6 @@ printf("%d ",value); if (value < 0) value = 0; -printf("%d\n",value); return value; } @@ -1263,7 +1259,7 @@ void SFG_createExplosion(RCL_Unit x, RCL_Unit y, RCL_Unit z) SFG_playerChangeHealth( -1 * SFG_getDamageValue(SFG_WEAPON_FIRE_TYPE_FIREBALL)); - for (uint8_t i = 0; i < SFG_currentLevel.monsterRecordCount; ++i) + for (uint16_t i = 0; i < SFG_currentLevel.monsterRecordCount; ++i) { SFG_MonsterRecord *monster = &(SFG_currentLevel.monsterRecords[i]); @@ -1301,6 +1297,25 @@ void SFG_createDust(RCL_Unit x, RCL_Unit y, RCL_Unit z) SFG_createProjectile(dust); } +uint8_t SFG_isInMeleeRange(RCL_Unit x0, RCL_Unit y0, RCL_Unit z0, RCL_Unit x1, + RCL_Unit y1, RCL_Unit z1) +{ + return + (SFG_taxicabDistance(x0,y0,x1,y1) <= SFG_MELEE_RANGE) && + (RCL_absVal(z0 - z1) <= SFG_MELEE_RANGE); +} + +void SFG_getMonsterWorldPosition(SFG_MonsterRecord *monster, RCL_Unit *x, + RCL_Unit *y, RCL_Unit *z) +{ + *x = SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[0]); + *y = SFG_MONSTER_COORD_TO_RCL_UNITS(monster->coords[1]); + *z = SFG_floorHeightAt( + SFG_MONSTER_COORD_TO_SQUARES(monster->coords[0]), + SFG_MONSTER_COORD_TO_SQUARES(monster->coords[1])) + + RCL_UNITS_PER_SQUARE / 2; +} + void SFG_monsterPerformAI(SFG_MonsterRecord *monster) { uint8_t state = SFG_MR_STATE(*monster); @@ -1394,21 +1409,18 @@ void SFG_monsterPerformAI(SFG_MonsterRecord *monster) uint8_t mX = SFG_MONSTER_COORD_TO_SQUARES(monster->coords[0]); uint8_t mY = SFG_MONSTER_COORD_TO_SQUARES(monster->coords[1]); + RCL_Unit pX, pY, pZ; + SFG_getMonsterWorldPosition(monster,&pX,&pY,&pZ); + 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 - ); + SFG_isInMeleeRange( + pX, + pY, + pZ, + SFG_player.camera.position.x, + SFG_player.camera.position.y, + SFG_player.camera.height + ); if (!isClose) { @@ -1440,13 +1452,18 @@ void SFG_monsterPerformAI(SFG_MonsterRecord *monster) state = SFG_MONSTER_STATE_GOING_S; } } - else + else // is close { + // melee, close-up attack + if (attackType == SFG_MONSTER_ATTACK_MELEE) { // melee attack state = SFG_MONSTER_STATE_ATTACKING; + + SFG_playerChangeHealth( + -1 * SFG_getDamageValue(SFG_WEAPON_FIRE_TYPE_MELEE)); } else // SFG_MONSTER_ATTACK_EXPLODE { @@ -1461,7 +1478,6 @@ void SFG_monsterPerformAI(SFG_MonsterRecord *monster) SFG_TILE_FLOOR_HEIGHT(tile) * SFG_WALL_HEIGHT_STEP + SFG_WALL_HEIGHT_STEP); monster->health = 0; - } } } @@ -1679,6 +1695,43 @@ void SFG_gameStep() direction += angleAdd; } } + else + { + // melee attack + + for (uint16_t i = 0; i < SFG_currentLevel.monsterRecordCount; ++i) + { + SFG_MonsterRecord *m = &(SFG_currentLevel.monsterRecords[i]); + + if (SFG_MR_STATE(*m) == SFG_MONSTER_STATE_INACTIVE) + continue; + + RCL_Unit pX, pY, pZ; + SFG_getMonsterWorldPosition(m,&pX,&pY,&pZ); + + if (!SFG_isInMeleeRange(pX,pY,pZ, + SFG_player.camera.position.x, + SFG_player.camera.position.y, + SFG_player.camera.height)) + continue; + + RCL_Vector2D toMonster; + + toMonster.x = pX - SFG_player.camera.position.x; + toMonster.y = pY - SFG_player.camera.position.y; + + if (RCL_vectorsAngleCos(SFG_player.direction,toMonster) >= + (RCL_UNITS_PER_SQUARE - SFG_PLAYER_MELEE_ANGLE)) + { + SFG_monsterChangeHealth(m, + -1 * SFG_getDamageValue(SFG_WEAPON_FIRE_TYPE_MELEE)); + + SFG_createDust(pX,pY,pZ); + + break; + } + } + } SFG_player.weaponCooldownStartFrame = SFG_gameFrame; } @@ -1840,7 +1893,7 @@ void SFG_gameStep() // handle player collision with level elements: // monsters: - for (uint8_t i = 0; i < SFG_currentLevel.monsterRecordCount; ++i) + for (uint16_t i = 0; i < SFG_currentLevel.monsterRecordCount; ++i) { SFG_MonsterRecord *m = &(SFG_currentLevel.monsterRecords[i]); @@ -1907,7 +1960,7 @@ void SFG_gameStep() // take, eliminate the item - for (uint8_t j = i; j < SFG_currentLevel.itemRecordCount - 1; ++j) + for (uint16_t j = i; j < SFG_currentLevel.itemRecordCount - 1; ++j) SFG_currentLevel.itemRecords[j] = SFG_currentLevel.itemRecords[j + 1]; @@ -2016,7 +2069,7 @@ void SFG_gameStep() // check collision with active level elements - for (uint8_t j = 0; j < SFG_currentLevel.monsterRecordCount; ++j) + for (uint16_t j = 0; j < SFG_currentLevel.monsterRecordCount; ++j) { SFG_MonsterRecord *m = &(SFG_currentLevel.monsterRecords[j]); @@ -2044,7 +2097,7 @@ void SFG_gameStep() } if (!eliminate) - for (uint8_t j = 0; j < SFG_currentLevel.itemRecordCount; ++j) + for (uint16_t j = 0; j < SFG_currentLevel.itemRecordCount; ++j) { const SFG_LevelElement *e = SFG_getActiveItemElement(j); @@ -2224,7 +2277,7 @@ void SFG_gameStep() if ((SFG_gameFrame - SFG_currentLevel.frameStart) % SFG_AI_UPDATE_FRAME_INTERVAL == 0) { - for (uint8_t i = 0; i < SFG_currentLevel.monsterRecordCount; ++i) + for (uint16_t i = 0; i < SFG_currentLevel.monsterRecordCount; ++i) { SFG_MonsterRecord *monster = &(SFG_currentLevel.monsterRecords[i]); uint8_t state = SFG_MR_STATE(*monster); @@ -2233,7 +2286,7 @@ void SFG_gameStep() { // remove dead - for (uint8_t j = i; j < SFG_currentLevel.monsterRecordCount - 1; ++j) + for (uint16_t j = i; j < SFG_currentLevel.monsterRecordCount - 1; ++j) SFG_currentLevel.monsterRecords[j] = SFG_currentLevel.monsterRecords[j + 1]; @@ -2546,7 +2599,7 @@ void SFG_draw() // draw sprites: // monster sprites: - for (uint8_t i = 0; i < SFG_currentLevel.monsterRecordCount; ++i) + for (uint16_t i = 0; i < SFG_currentLevel.monsterRecordCount; ++i) { SFG_MonsterRecord m = SFG_currentLevel.monsterRecords[i]; @@ -2591,7 +2644,7 @@ void SFG_draw() } // item sprites: - for (uint8_t i = 0; i < SFG_currentLevel.itemRecordCount; ++i) + for (uint16_t i = 0; i < SFG_currentLevel.itemRecordCount; ++i) if (SFG_currentLevel.itemRecords[i] & SFG_ITEM_RECORD_ACTIVE_MASK) { RCL_Vector2D worldPosition;