sovereignx/src/fldeff_cut.c

614 lines
19 KiB
C
Raw Normal View History

#include "global.h"
2018-06-15 23:45:48 +01:00
#include "field_camera.h"
#include "field_effect.h"
#include "event_object_movement.h"
#include "field_player_avatar.h"
#include "fieldmap.h"
#include "event_obj_lock.h"
#include "metatile_behavior.h"
#include "party_menu.h"
#include "overworld.h"
#include "script.h"
#include "sound.h"
#include "sprite.h"
#include "task.h"
#include "trig.h"
#include "malloc.h"
#include "constants/event_objects.h"
#include "constants/songs.h"
#include "constants/abilities.h"
// tileset 0 as first
#define METATILE_ID_GRASS 0x1
#define METATILE_ID_POKE_GRASS 0xD
#define METATILE_ID_POKE_GRASS_TREE_UP 0x25
#define METATILE_ID_GRASS_TREE_UP 0xE
#define METATILE_ID_POKE_GRASS_TREE_LEFT 0x1C6
#define METATILE_ID_POKE_GRASS_TREE_RIGHT 0x1C7
#define METATILE_ID_GRASS_TREE_LEFT 0x1CE
#define METATILE_ID_GRASS_TREE_RIGHT 0x1CF
#define METATILE_ID_POKE_TALL_GRASS 0x15
// tileset 6 as second
#define METATILE_ID_POKE_STEP_LAVA_GRASS 0x206
#define METATILE_ID_POKE_LAVA_GRASS 0x207
#define METATILE_ID_LAVA_FIELD 0x271
// tileset 7 as second
#define METATILE_ID_POKE_ASH_GRASS 0x20A
#define METATILE_ID_POKE_STEP_ASH_GRASS 0x212
#define METATILE_ID_ASH 0x218
// tileset 8 as second
#define METATILE_ID_POKE_TALL_GRASS_START 0x208
#define METATILE_ID_SECRET_BASE_LEFT_TALL_GRASS 0x279
#define METATILE_ID_SECRET_BASE_CENTER_TALL_GRASS 0x27A
#define METATILE_ID_SECRET_BASE_RIGHT_TALL_GRASS 0x27B
#define METATILE_ID_SECRET_BASE_LEFT_POKE_TALL_GRASS 0x281
#define METATILE_ID_SECRET_BASE_CENTER_POKE_TALL_GRASS 0x282
#define METATILE_ID_SECRET_BASE_RIGHT_POKE_TALL_GRASS 0x283
extern bool8 SetLastTalkedObjectInFrontOfPlayer(u8);
extern u8 oei_task_add(void);
extern struct MapPosition gPlayerFacingPosition;
extern u8 *gCutGrassSpriteArrayPtr;
extern const u8 Route103_EventScript_290705[];
extern const u8 gFieldEffectPic_CutGrass[];
extern const u16 gFieldEffectObjectPalette6[];
#define CUT_NORMAL_SIDE 3
#define CUT_NORMAL_AREA CUT_NORMAL_SIDE * CUT_NORMAL_SIDE
/* P - player
X - cut area
XXX
XPX
XXX
*/
2018-06-15 23:45:48 +01:00
#define CUT_HYPER_SIDE 5
#define CUT_HYPER_AREA CUT_HYPER_SIDE * CUT_HYPER_SIDE
/* P - player
X - cut area
2018-06-15 23:45:48 +01:00
XXXXX
XXXXX
XXPXX
XXXXX
XXXXX
*/
IWRAM_DATA u8 gUnknown_03001100;
IWRAM_DATA u8 gUnknown_03001101;
IWRAM_DATA u8 gUnknown_03001102;
IWRAM_DATA u32 fldeff_cut_unused_03001104;
2018-06-15 23:45:48 +01:00
IWRAM_DATA bool8 gUnknown_03001108[CUT_HYPER_AREA];
struct HyperCutterUnk
{
s8 x;
s8 y;
u8 unk2[2];
};
const struct HyperCutterUnk gUnknown_0857C608[] =
{
{-2, -2, {1}},
{-1, -2, {1}},
{0, -2, {2}},
{1, -2, {3}},
{2, -2, {3}},
{-2, -1, {1}},
{2, -1, {3}},
{-2, 0, {4}},
{2, 0, {6}},
{-2, 1, {7}},
{2, 1, {9}},
{-2, 2, {7}},
{-1, 2, {7}},
{0, 2, {8}},
{1, 2, {9}},
{2, 2, {9}},
};
const struct OamData gOamData_CutGrass =
{
.y = 0,
.affineMode = 0,
.objMode = 0,
.mosaic = 0,
.bpp = 0,
.shape = 0,
.x = 0,
.matrixNum = 0,
.size = 0,
.tileNum = 1,
.priority = 1,
.paletteNum = 1,
.affineParam = 0,
};
const union AnimCmd gSpriteAnim_CutGrass[] =
{
ANIMCMD_FRAME(0, 30),
ANIMCMD_JUMP(0),
};
const union AnimCmd *const gSpriteAnimTable_CutGrass[] =
{
gSpriteAnim_CutGrass,
};
const struct SpriteFrameImage gSpriteImageTable_CutGrass[] =
{
{gFieldEffectPic_CutGrass, 0x20},
};
const struct SpritePalette gFieldEffectObjectPaletteInfo6 = {gFieldEffectObjectPalette6, 0x1000};
void FieldCallback_CutTree(void);
void FieldCallback_CutGrass(void);
void StartCutTreeFieldEffect(void);
void StartCutGrassFieldEffect(void);
void SetCutGrassMetatile(s16, s16);
void SetCutGrassMetatiles(s16, s16);
void CutGrassSpriteCallback1(struct Sprite *);
void CutGrassSpriteCallback2(struct Sprite *);
void CutGrassSpriteCallbackEnd(struct Sprite *);
void HandleTallGrassOnHyper(u8, s16, s16);
const struct SpriteTemplate gSpriteTemplate_CutGrass =
{
.tileTag = 0xFFFF,
.paletteTag = 0x1000,
.oam = &gOamData_CutGrass,
.anims = gSpriteAnimTable_CutGrass,
.images = gSpriteImageTable_CutGrass,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = CutGrassSpriteCallback1,
};
bool8 SetUpFieldMove_Cut(void)
{
s16 x, y;
u8 i, j;
u8 tileBehavior;
u8 userAbility;
bool8 array[CUT_NORMAL_AREA];
bool8 ret;
if (SetLastTalkedObjectInFrontOfPlayer(EVENT_OBJ_GFX_CUTTABLE_TREE) == TRUE)
{
// Standing in front of cuttable tree.
gFieldCallback2 = FieldCallback_PrepareFadeInFromMenu;
gPostMenuFieldCallback = FieldCallback_CutTree;
return TRUE;
}
else
{
PlayerGetDestCoords(&gPlayerFacingPosition.x, &gPlayerFacingPosition.y);
userAbility = GetMonAbility(&gPlayerParty[GetCursorSelectionMonId()]);
if (userAbility == ABILITY_HYPER_CUTTER)
{
gUnknown_03001100 = 5;
gUnknown_03001101 = 2;
gUnknown_03001102 = 2;
}
else
{
gUnknown_03001100 = 3;
gUnknown_03001101 = 1;
gUnknown_03001102 = 1;
}
for (i = 0; i < CUT_NORMAL_AREA; i++)
array[i] = FALSE;
for (i = 0; i < CUT_HYPER_AREA; i++)
gUnknown_03001108[i] = FALSE;
ret = FALSE;
for (i = 0; i < 3; i++)
{
y = i - 1 + gPlayerFacingPosition.y;
for (j = 0; j < 3; j++)
{
x = j - 1 + gPlayerFacingPosition.x;
if (MapGridGetZCoordAt(x, y) == gPlayerFacingPosition.height)
{
tileBehavior = MapGridGetMetatileBehaviorAt(x, y);
if (MetatileBehavior_IsPokeGrass(tileBehavior) == TRUE
|| MetatileBehavior_IsAshGrass(tileBehavior) == TRUE)
{
// Standing in front of grass.
gUnknown_03001108[6 + (i * 5) + j] = TRUE;
ret = TRUE;
}
if (MapGridIsImpassableAt(x, y) == TRUE)
{
array[i * 3 + j] = FALSE;
}
else
{
array[i * 3 + j] = TRUE;
if (MetatileBehavior_IsCuttableGrass(tileBehavior) == TRUE)
gUnknown_03001108[6 + (i * 5) + j] = TRUE;
}
}
else
{
array[i * 3 + j] = FALSE;
}
}
}
if (userAbility != ABILITY_HYPER_CUTTER)
{
if (ret == TRUE)
{
gFieldCallback2 = FieldCallback_PrepareFadeInFromMenu;
gPostMenuFieldCallback = FieldCallback_CutGrass;
}
}
else
{
bool8 r7;
for (i = 0; i < 16; i++)
{
x = gPlayerFacingPosition.x + gUnknown_0857C608[i].x;
y = gPlayerFacingPosition.y + gUnknown_0857C608[i].y;
r7 = TRUE;
j = 0;
while (1)
{
if (gUnknown_0857C608[i].unk2[j] == 0)
break;
if (array[(u8)(gUnknown_0857C608[i].unk2[j] - 1)] == FALSE)
{
r7 = FALSE;
break;
}
if (++j >= 2)
break;
}
if (r7 == TRUE)
{
if (MapGridGetZCoordAt(x, y) == gPlayerFacingPosition.height)
{
u8 r6 = ((gUnknown_0857C608[i].y * 5) + 12) + (gUnknown_0857C608[i].x);
tileBehavior = MapGridGetMetatileBehaviorAt(x, y);
if (MetatileBehavior_IsPokeGrass(tileBehavior) == TRUE
|| MetatileBehavior_IsAshGrass(tileBehavior) == TRUE)
{
gFieldCallback2 = FieldCallback_PrepareFadeInFromMenu;
gPostMenuFieldCallback = FieldCallback_CutGrass;
gUnknown_03001108[r6] = r7;
ret = TRUE;
}
else
{
if (MetatileBehavior_IsCuttableGrass(tileBehavior) == TRUE)
gUnknown_03001108[r6] = TRUE;
}
}
}
}
if (ret == TRUE)
{
gFieldCallback2 = FieldCallback_PrepareFadeInFromMenu;
gPostMenuFieldCallback = FieldCallback_CutGrass;
}
}
return ret;
}
}
void FieldCallback_CutGrass(void)
{
FieldEffectStart(FLDEFF_USE_CUT_ON_GRASS);
gFieldEffectArguments[0] = GetCursorSelectionMonId();
}
bool8 FldEff_UseCutOnGrass(void)
{
u8 taskId = oei_task_add();
gTasks[taskId].data[8] = (u32)StartCutGrassFieldEffect >> 16;
gTasks[taskId].data[9] = (u32)StartCutGrassFieldEffect;
IncrementGameStat(GAME_STAT_USED_CUT);
return FALSE;
}
void FieldCallback_CutTree(void)
{
gFieldEffectArguments[0] = GetCursorSelectionMonId();
ScriptContext1_SetupScript(Route103_EventScript_290705);
}
bool8 FldEff_UseCutOnTree(void)
{
u8 taskId = oei_task_add();
gTasks[taskId].data[8] = (u32)StartCutTreeFieldEffect >> 16;
gTasks[taskId].data[9] = (u32)StartCutTreeFieldEffect;
IncrementGameStat(GAME_STAT_USED_CUT);
return FALSE;
}
void StartCutGrassFieldEffect(void)
{
FieldEffectActiveListRemove(FLDEFF_USE_CUT_ON_GRASS);
FieldEffectStart(FLDEFF_CUT_GRASS);
}
bool8 FldEff_CutGrass(void)
{
s16 x, y;
u8 tileBehavior;
u8 i;
for (i = 0, PlaySE(SE_W015), PlayerGetDestCoords(&gPlayerFacingPosition.x, &gPlayerFacingPosition.y); i < 25; i++)
{
if (gUnknown_03001108[i] == TRUE)
{
s8 xAdd = (i % 5) - 2;
s8 yAdd = (i / 5) - 2;
x = xAdd + gPlayerFacingPosition.x;
y = yAdd + gPlayerFacingPosition.y;
SetCutGrassMetatile(x, y);
sub_808E75C(x, y);
}
}
SetCutGrassMetatiles(gPlayerFacingPosition.x - gUnknown_03001101, gPlayerFacingPosition.y + (~gUnknown_03001102));
DrawWholeMapView();
gCutGrassSpriteArrayPtr = AllocZeroed(8);
// populate sprite ID array
for (i = 0; i < 8; i++)
{
gCutGrassSpriteArrayPtr[i] = CreateSprite(&gSpriteTemplate_CutGrass,
gSprites[gPlayerAvatar.spriteId].oam.x + 8, gSprites[gPlayerAvatar.spriteId].oam.y + 20, 0);
gSprites[gCutGrassSpriteArrayPtr[i]].data[2] = 32 * i;
}
return FALSE;
}
// set map grid metatile depending on x, y
void SetCutGrassMetatile(s16 x, s16 y)
{
s32 metatileId = MapGridGetMetatileIdAt(x, y);
switch (metatileId)
{
case METATILE_ID_POKE_TALL_GRASS_START:
case METATILE_ID_POKE_TALL_GRASS:
case METATILE_ID_POKE_GRASS:
MapGridSetMetatileIdAt(x, y, METATILE_ID_GRASS);
break;
case METATILE_ID_POKE_GRASS_TREE_LEFT:
MapGridSetMetatileIdAt(x, y, METATILE_ID_GRASS_TREE_LEFT);
break;
case METATILE_ID_POKE_GRASS_TREE_RIGHT:
MapGridSetMetatileIdAt(x, y, METATILE_ID_GRASS_TREE_RIGHT);
break;
case METATILE_ID_SECRET_BASE_LEFT_POKE_TALL_GRASS:
MapGridSetMetatileIdAt(x, y, METATILE_ID_SECRET_BASE_LEFT_TALL_GRASS);
break;
case METATILE_ID_SECRET_BASE_CENTER_POKE_TALL_GRASS:
MapGridSetMetatileIdAt(x, y, METATILE_ID_SECRET_BASE_CENTER_TALL_GRASS);
break;
case METATILE_ID_SECRET_BASE_RIGHT_POKE_TALL_GRASS:
MapGridSetMetatileIdAt(x, y, METATILE_ID_SECRET_BASE_RIGHT_TALL_GRASS);
break;
case METATILE_ID_POKE_STEP_LAVA_GRASS:
case METATILE_ID_POKE_LAVA_GRASS:
MapGridSetMetatileIdAt(x, y, METATILE_ID_LAVA_FIELD);
break;
case METATILE_ID_POKE_STEP_ASH_GRASS:
case METATILE_ID_POKE_ASH_GRASS:
MapGridSetMetatileIdAt(x, y, METATILE_ID_ASH);
break;
case METATILE_ID_POKE_GRASS_TREE_UP:
MapGridSetMetatileIdAt(x, y, METATILE_ID_GRASS_TREE_UP);
break;
}
}
enum
{
TALL_GRASS_NONE,
TALL_GRASS_FIELD,
TALL_GRASS_BASE_LEFT,
TALL_GRASS_BASE_CENTER,
TALL_GRASS_BASE_RIGHT
};
u8 GetTallGrassCaseAt(s16 x, s16 y)
{
u16 metatileId = MapGridGetMetatileIdAt(x, y);
if (metatileId == METATILE_ID_GRASS)
return TALL_GRASS_FIELD;
else if (metatileId == METATILE_ID_SECRET_BASE_LEFT_TALL_GRASS)
return TALL_GRASS_BASE_LEFT;
else if (metatileId == METATILE_ID_SECRET_BASE_CENTER_TALL_GRASS)
return TALL_GRASS_BASE_CENTER;
else if (metatileId == METATILE_ID_SECRET_BASE_RIGHT_TALL_GRASS)
return TALL_GRASS_BASE_RIGHT;
else
return TALL_GRASS_NONE;
}
void SetCutGrassMetatiles(s16 x, s16 y)
{
s16 i;
s16 lowerY = y + gUnknown_03001100;
for (i = 0; i < gUnknown_03001100; i++)
{
s16 currentX = x + i;
if (MapGridGetMetatileIdAt(currentX, y) == METATILE_ID_POKE_TALL_GRASS)
{
switch (GetTallGrassCaseAt(currentX, y + 1))
{
case TALL_GRASS_FIELD:
MapGridSetMetatileIdAt(currentX, y + 1, METATILE_ID_POKE_TALL_GRASS_START);
break;
case TALL_GRASS_BASE_LEFT:
MapGridSetMetatileIdAt(currentX, y + 1, METATILE_ID_SECRET_BASE_LEFT_POKE_TALL_GRASS);
break;
case TALL_GRASS_BASE_CENTER:
MapGridSetMetatileIdAt(currentX, y + 1, METATILE_ID_SECRET_BASE_CENTER_POKE_TALL_GRASS);
break;
case TALL_GRASS_BASE_RIGHT:
MapGridSetMetatileIdAt(currentX, y + 1, METATILE_ID_SECRET_BASE_RIGHT_POKE_TALL_GRASS);
break;
}
}
if (MapGridGetMetatileIdAt(currentX, lowerY) == METATILE_ID_GRASS)
{
if (MapGridGetMetatileIdAt(currentX, lowerY + 1) == METATILE_ID_POKE_TALL_GRASS_START)
MapGridSetMetatileIdAt(currentX, lowerY + 1, METATILE_ID_GRASS);
if (MapGridGetMetatileIdAt(currentX, lowerY + 1) == METATILE_ID_SECRET_BASE_LEFT_POKE_TALL_GRASS)
MapGridSetMetatileIdAt(currentX, lowerY + 1, METATILE_ID_SECRET_BASE_LEFT_TALL_GRASS);
if (MapGridGetMetatileIdAt(currentX, lowerY + 1) == METATILE_ID_SECRET_BASE_CENTER_POKE_TALL_GRASS)
MapGridSetMetatileIdAt(currentX, lowerY + 1, METATILE_ID_SECRET_BASE_CENTER_TALL_GRASS);
if (MapGridGetMetatileIdAt(currentX, lowerY + 1) == METATILE_ID_SECRET_BASE_RIGHT_POKE_TALL_GRASS)
MapGridSetMetatileIdAt(currentX, lowerY + 1, METATILE_ID_SECRET_BASE_RIGHT_TALL_GRASS);
}
}
if (gUnknown_03001100 == CUT_HYPER_SIDE)
{
HandleTallGrassOnHyper(0, x, y);
HandleTallGrassOnHyper(1, x, y);
}
}
void HandleTallGrassOnHyper(u8 caseId, s16 x, s16 y)
{
s16 newX;
bool8 arr[3];
if (caseId == 0)
{
arr[0] = gUnknown_03001108[5];
arr[1] = gUnknown_03001108[10];
arr[2] = gUnknown_03001108[15];
newX = x;
}
else if (caseId == 1)
{
arr[0] = gUnknown_03001108[9];
arr[1] = gUnknown_03001108[14];
arr[2] = gUnknown_03001108[19];
newX = x + 4;
}
else // invalid case
{
return;
}
if (arr[0] == TRUE)
{
if (MapGridGetMetatileIdAt(newX, y + 3) == METATILE_ID_POKE_TALL_GRASS_START)
MapGridSetMetatileIdAt(newX, y + 3, METATILE_ID_GRASS);
if (MapGridGetMetatileIdAt(newX, y + 3) == METATILE_ID_SECRET_BASE_LEFT_POKE_TALL_GRASS)
MapGridSetMetatileIdAt(newX, y + 3, METATILE_ID_SECRET_BASE_LEFT_TALL_GRASS);
if (MapGridGetMetatileIdAt(newX, y + 3) == METATILE_ID_SECRET_BASE_CENTER_POKE_TALL_GRASS)
MapGridSetMetatileIdAt(newX, y + 3, METATILE_ID_SECRET_BASE_CENTER_TALL_GRASS);
if (MapGridGetMetatileIdAt(newX, y + 3) == METATILE_ID_SECRET_BASE_RIGHT_POKE_TALL_GRASS)
MapGridSetMetatileIdAt(newX, y + 3, METATILE_ID_SECRET_BASE_RIGHT_TALL_GRASS);
}
if (arr[1] == TRUE)
{
if (MapGridGetMetatileIdAt(newX, y + 2) == METATILE_ID_POKE_TALL_GRASS)
{
switch (GetTallGrassCaseAt(newX, y + 3))
{
case TALL_GRASS_FIELD:
MapGridSetMetatileIdAt(newX, y + 3, METATILE_ID_POKE_TALL_GRASS_START);
break;
case TALL_GRASS_BASE_LEFT:
MapGridSetMetatileIdAt(newX, y + 3, METATILE_ID_SECRET_BASE_LEFT_POKE_TALL_GRASS);
break;
case TALL_GRASS_BASE_CENTER:
MapGridSetMetatileIdAt(newX, y + 3, METATILE_ID_SECRET_BASE_CENTER_POKE_TALL_GRASS);
break;
case TALL_GRASS_BASE_RIGHT:
MapGridSetMetatileIdAt(newX, y + 3, METATILE_ID_SECRET_BASE_RIGHT_POKE_TALL_GRASS);
break;
}
}
if (MapGridGetMetatileIdAt(newX, y + 4) == METATILE_ID_POKE_TALL_GRASS_START)
MapGridSetMetatileIdAt(newX, y + 4, METATILE_ID_GRASS);
if (MapGridGetMetatileIdAt(newX, y + 4) == METATILE_ID_SECRET_BASE_LEFT_POKE_TALL_GRASS)
MapGridSetMetatileIdAt(newX, y + 4, METATILE_ID_SECRET_BASE_LEFT_TALL_GRASS);
if (MapGridGetMetatileIdAt(newX, y + 4) == METATILE_ID_SECRET_BASE_CENTER_POKE_TALL_GRASS)
MapGridSetMetatileIdAt(newX, y + 4, METATILE_ID_SECRET_BASE_CENTER_TALL_GRASS);
if (MapGridGetMetatileIdAt(newX, y + 4) == METATILE_ID_SECRET_BASE_RIGHT_POKE_TALL_GRASS)
MapGridSetMetatileIdAt(newX, y + 4, METATILE_ID_SECRET_BASE_RIGHT_TALL_GRASS);
}
if (arr[2] == TRUE)
{
if (MapGridGetMetatileIdAt(newX, y + 3) == METATILE_ID_POKE_TALL_GRASS)
{
switch (GetTallGrassCaseAt(newX, y + 4))
{
case TALL_GRASS_FIELD:
MapGridSetMetatileIdAt(newX, y + 4, METATILE_ID_POKE_TALL_GRASS_START);
break;
case TALL_GRASS_BASE_LEFT:
MapGridSetMetatileIdAt(newX, y + 4, METATILE_ID_SECRET_BASE_LEFT_POKE_TALL_GRASS);
break;
case TALL_GRASS_BASE_CENTER:
MapGridSetMetatileIdAt(newX, y + 4, METATILE_ID_SECRET_BASE_CENTER_POKE_TALL_GRASS);
break;
case TALL_GRASS_BASE_RIGHT:
MapGridSetMetatileIdAt(newX, y + 4, METATILE_ID_SECRET_BASE_RIGHT_POKE_TALL_GRASS);
break;
}
}
}
}
void CutGrassSpriteCallback1(struct Sprite *sprite)
{
sprite->data[0] = 8;
sprite->data[1] = 0;
sprite->data[3] = 0;
sprite->callback = CutGrassSpriteCallback2;
}
2018-06-15 23:45:48 +01:00
void CutGrassSpriteCallback2(struct Sprite *sprite)
{
sprite->pos2.x = Sin(sprite->data[2], sprite->data[0]);
sprite->pos2.y = Cos(sprite->data[2], sprite->data[0]);
2018-06-15 23:45:48 +01:00
sprite->data[2] = (sprite->data[2] + 8) & 0xFF;
sprite->data[0] += 1 + (sprite->data[3] >> 2); // right shift by 2 is dividing by 4
sprite->data[3]++;
2018-06-15 23:45:48 +01:00
if (sprite->data[1] != 28)
sprite->data[1]++;
else
sprite->callback = CutGrassSpriteCallbackEnd; // done rotating the grass, execute clean up function
}