# pragma region License
/*
License ( OLC - 3 )
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
Copyright 2024 Joshua Sigona < sigonasr2 @ gmail . com >
Redistribution and use in source and binary forms , with or without modification ,
are permitted provided that the following conditions are met :
1. Redistributions or derivations of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2. Redistributions or derivative works in binary form must reproduce the above
copyright notice . This list of conditions and the following disclaimer must be
reproduced in the documentation and / or other materials provided with the distribution .
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
prior written permission .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND ANY
EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT ,
INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED
TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR
BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE .
Portions of this software are copyright © 2024 The FreeType
Project ( www . freetype . org ) . Please see LICENSE_FT . txt for more information .
All rights reserved .
*/
# pragma endregion
# include "ItemDrop.h"
# include "olcUTIL_Geometry2D.h"
# include "AdventuresInLestoria.h"
# include "SoundEffect.h"
INCLUDE_game
INCLUDE_GFX
float ItemDrop : : gravity ;
std : : vector < ItemDrop > ItemDrop : : drops ;
void ItemDrop : : Initialize ( ) {
gravity = " ItemDrop.Item Drop Gravity " _F ;
}
ItemDrop : : ItemDrop ( const ItemInfo * item , const vf2d pos , const bool isUpper )
: item ( item ) , pos ( pos ) , upperLevel ( isUpper ) {
const bool HasBossArenaBounds = game - > GetCurrentMap ( ) . GetMapType ( ) = = Map : : MapType : : BOSS ;
if ( HasBossArenaBounds ) {
const geom2d : : rect < int > arenaBounds = game - > GetZones ( ) . at ( " BossArena " ) [ 0 ] . zone ;
this - > pos . x = std : : clamp ( this - > pos . x , float ( arenaBounds . pos . x ) , float ( arenaBounds . pos . x + arenaBounds . size . x ) ) ;
this - > pos . y = std : : clamp ( this - > pos . y , float ( arenaBounds . pos . y ) , float ( arenaBounds . pos . y + arenaBounds . size . y ) ) ;
}
speed . x = util : : random_range ( " ItemDrop.Item Drop Horizontal Speed " _f [ 0 ] , " ItemDrop.Item Drop Horizontal Speed " _f [ 1 ] ) ;
speed . y = util : : random_range ( " ItemDrop.Item Drop Vertical Speed " _f [ 0 ] , " ItemDrop.Item Drop Vertical Speed " _f [ 1 ] ) ;
zSpeed = " ItemDrop.Item Drop Initial Rise Speed " _F ;
randomSpinOffset = util : : random ( PI / 2 ) ;
}
vf2d ItemDrop : : GetPos ( ) const {
return pos ;
}
bool ItemDrop : : OnUpperLevel ( ) {
return upperLevel ;
}
void ItemDrop : : Draw ( ) const {
# pragma region Item Drop Shadow Rendering
if ( GetZ ( ) > 0 ) {
vf2d shadowScale = vf2d { 8 * " ItemDrop.Item Drop Scale " _F / 3.f , 1 } / std : : max ( 1.f , GetZ ( ) / 24 ) ;
game - > view . DrawDecal ( GetPos ( ) - vf2d { 3 , 3 } * shadowScale / 2 + vf2d { 0 , 6 * " ItemDrop.Item Drop Scale " _F } , GFX [ " circle.png " ] . Decal ( ) , shadowScale , BLACK ) ;
}
# pragma endregion
float yOffset = 0 ;
if ( GetZ ( ) = = 0 ) {
yOffset = sin ( ( game - > levelTime + randomSpinOffset ) * 3 ) * 0.5f ;
}
game - > view . DrawRotatedDecal ( pos - vf2d { 0 , GetZ ( ) + yOffset } , GFX [ " skill_overlay_icon_overlay.png " ] . Decal ( ) , 0 , GFX [ " skill_overlay_icon_overlay.png " ] . Decal ( ) - > sprite - > Size ( ) / 2 , { " ItemDrop.Item Drop Scale " _F , " ItemDrop.Item Drop Scale " _F } , YELLOW ) ;
game - > view . DrawRotatedDecal ( pos - vf2d { 0 , GetZ ( ) + yOffset } , const_cast < Decal * > ( item - > Decal ( ) ) , 0 , item - > Decal ( ) - > sprite - > Size ( ) / 2 , { " ItemDrop.Item Drop Scale " _F , " ItemDrop.Item Drop Scale " _F } , { 255 , 255 , 255 , 128 } ) ;
game - > SetDecalMode ( DecalMode : : ADDITIVE ) ;
game - > view . DrawRotatedDecal ( pos - vf2d { 0 , GetZ ( ) + yOffset } , const_cast < Decal * > ( item - > Decal ( ) ) , 0 , item - > Decal ( ) - > sprite - > Size ( ) / 2 , { " ItemDrop.Item Drop Scale " _F , " ItemDrop.Item Drop Scale " _F } , { uint8_t ( abs ( sin ( game - > levelTime * 1.5 ) * 255.f ) ) , uint8_t ( abs ( sin ( game - > levelTime * 1.5 ) * 255.f ) ) , uint8_t ( abs ( sin ( game - > levelTime * 1.5 ) * 255.f ) ) , 128 } ) ;
game - > SetDecalMode ( DecalMode : : NORMAL ) ;
}
void ItemDrop : : UpdateDrops ( float fElapsedTime ) {
for ( ItemDrop & drop : drops ) {
# pragma region Handle Z Speed
drop . z + = drop . zSpeed * fElapsedTime ;
if ( drop . z < = 0 ) {
drop . zSpeed = 0 ;
drop . z = 0 ;
}
else {
drop . zSpeed + = gravity * fElapsedTime ;
drop . pos + = drop . speed * fElapsedTime ;
}
# pragma endregion
# pragma region Check for Suction / Player pull-in
if ( drop . zSpeed = = 0 & & drop . OnUpperLevel ( ) = = game - > GetPlayer ( ) - > OnUpperLevel ( ) ) {
geom2d : : line < float > lineTo = geom2d : : line < float > ( drop . pos , game - > GetPlayer ( ) - > GetPos ( ) ) ;
float dist = lineTo . length ( ) ;
if ( dist < = " ItemDrop.Item Drop Suction Range " _F ) {
vf2d pointVel = lineTo . vector ( ) . norm ( ) ;
float moveDistance = ( 1.f / std : : min ( 48.f , dist ) ) * " ItemDrop.Item Drop Suction Strength " _F * fElapsedTime ;
if ( moveDistance > dist ) {
drop . pos = game - > GetPlayer ( ) - > GetPos ( ) ;
drop . collected = true ;
} else {
drop . pos + = pointVel * moveDistance ;
}
}
}
# pragma endregion
# pragma region Handle Upper / Lower Level Zone Intersecting
if ( drop . speed . mag ( ) > 0 ) {
const std : : map < std : : string , std : : vector < ZoneData > > & zoneData = game - > GetZones ( game - > GetCurrentLevel ( ) ) ;
for ( const ZoneData & upperLevelZone : zoneData . at ( " UpperZone " ) ) {
if ( geom2d : : overlaps ( upperLevelZone . zone , drop . pos ) ) {
drop . upperLevel = true ;
}
}
for ( const ZoneData & lowerLevelZone : zoneData . at ( " LowerZone " ) ) {
if ( geom2d : : overlaps ( lowerLevelZone . zone , drop . pos ) ) {
drop . upperLevel = false ;
}
}
}
# pragma endregion
}
std : : erase_if ( drops , [ ] ( ItemDrop & drop ) {
if ( drop . collected ) {
Inventory : : AddItem ( drop . GetItem ( ) - > Name ( ) , 1 , true ) ;
ItemOverlay : : AddToItemOverlay ( * drop . GetItem ( ) ) ;
SoundEffect : : PlaySFX ( " Collect Item " , SoundEffect : : CENTERED ) ;
return true ;
}
return false ;
} ) ;
ItemOverlay : : Update ( ) ;
}
float ItemDrop : : GetZ ( ) const {
return z ;
}
void ItemDrop : : SpawnItem ( const ItemInfo * item , vf2d pos , bool isUpper ) {
drops . push_back ( ItemDrop { item , pos , isUpper } ) ;
}
const ItemInfo * ItemDrop : : GetItem ( ) const {
return item ;
}
const std : : vector < ItemDrop > & ItemDrop : : GetDrops ( ) {
return ItemDrop : : drops ;
}
void ItemDrop : : ClearDrops ( ) {
ItemDrop : : drops . clear ( ) ;
}