2018-01-24 08:16:52 +01:00
/*
Copyright ( C ) 2018 Parallel Realities
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
# include "hub.h"
static void unlockAllLevels ( void ) ;
static void unlockMission ( char * id ) ;
static int getMissionStatus ( char * id ) ;
static void loadMissions ( void ) ;
static void unlockNeighbouringMission ( HubMission * sourceMission ) ;
static int missionComparator ( const void * a , const void * b ) ;
2018-02-16 23:50:55 +01:00
static HubMission * getMissionAt ( int x , int y ) ;
static void logic ( void ) ;
static void draw ( void ) ;
2018-01-24 08:16:52 +01:00
static HubMission hubMissionHead ;
static HubMission * hubMissionTail ;
2018-02-16 23:50:55 +01:00
static HubMission * selectedMission ;
static Atlas * worldMap ;
static Atlas * alert ;
static Atlas * clouds ;
static Texture * atlasTexture ;
static int completedMissions ;
static int numMissions ;
static float blipSize ;
static float blipValue ;
2018-01-24 08:16:52 +01:00
void initHub ( void )
{
2018-02-16 23:50:55 +01:00
int unlockedMissions , unlockTeeka ;
HubMission * mission , * teeka ;
2018-01-24 08:16:52 +01:00
Tuple * t ;
memset ( & hubMissionHead , 0 , sizeof ( HubMission ) ) ;
hubMissionTail = & hubMissionHead ;
2018-02-16 23:50:55 +01:00
atlasTexture = getTexture ( " gfx/atlas/atlas.png " ) ;
worldMap = getImageFromAtlas ( " gfx/hub/worldMap.jpg " ) ;
alert = getImageFromAtlas ( " gfx/hub/alert.png " ) ;
clouds = getImageFromAtlas ( " gfx/hub/clouds.png " ) ;
2018-01-24 08:16:52 +01:00
loadMissions ( ) ;
if ( dev . cheatLevels )
{
unlockAllLevels ( ) ;
}
2018-02-16 23:50:55 +01:00
numMissions = 0 ;
2018-01-24 08:16:52 +01:00
unlockedMissions = 0 ;
2018-02-16 23:50:55 +01:00
completedMissions = 0 ;
unlockTeeka = 1 ;
blipValue = 0 ;
2018-01-24 08:16:52 +01:00
for ( t = game . missionStatusHead . next ; t ! = NULL ; t = t - > next )
{
if ( t - > value . i ! = MS_INCOMPLETE )
{
unlockedMissions + + ;
}
2018-02-16 23:50:55 +01:00
if ( t - > value . i = = MS_COMPLETE )
{
completedMissions + + ;
}
2018-01-24 08:16:52 +01:00
}
for ( mission = hubMissionHead . next ; mission ! = NULL ; mission = mission - > next )
{
2018-02-16 23:50:55 +01:00
if ( mission - > unlockCount < = unlockedMissions | | dev . cheatLevels )
2018-01-24 08:16:52 +01:00
{
2018-02-16 23:50:55 +01:00
unlockMission ( mission - > id ) ;
}
mission - > status = getMissionStatus ( mission - > id ) ;
if ( strcmp ( mission - > id , " teeka " ) = = 0 )
{
teeka = mission ;
2018-01-24 08:16:52 +01:00
}
2018-02-16 23:50:55 +01:00
else if ( mission - > status = = MS_LOCKED )
2018-01-24 08:16:52 +01:00
{
2018-02-16 23:50:55 +01:00
unlockTeeka = 0 ;
2018-01-24 08:16:52 +01:00
}
2018-02-16 23:50:55 +01:00
numMissions + + ;
2018-01-24 08:16:52 +01:00
}
for ( mission = hubMissionHead . next ; mission ! = NULL ; mission = mission - > next )
{
if ( mission - > status = = MS_COMPLETE | | mission - > status = = MS_MISSING_HEART_CELL | | mission - > status = = MS_PARTIAL )
{
unlockNeighbouringMission ( mission ) ;
}
if ( mission - > status = = MS_MISSING_HEART_CELL )
{
2018-01-28 17:14:17 +01:00
STRNCPY ( mission - > description , _ ( " All objectives for this misson have been completed. However, there is a Cell or a Heart left to find. See if you can locate it. " ) , MAX_DESCRIPTION_LENGTH ) ;
2018-01-24 08:16:52 +01:00
}
}
2018-02-16 23:50:55 +01:00
if ( unlockTeeka )
{
teeka - > status = MS_INCOMPLETE ;
}
app . delegate . logic = & logic ;
app . delegate . draw = & draw ;
app . hideMouse = 0 ;
}
static void logic ( void )
{
HubMission * m ;
blipValue + = 0.1 ;
blipSize = 64 + ( sin ( blipValue ) * 16 ) ;
m = NULL ;
if ( app . mouse . button [ SDL_BUTTON_LEFT ] )
{
m = getMissionAt ( app . mouse . x , app . mouse . y ) ;
if ( m ! = NULL )
{
selectedMission = m ;
app . mouse . button [ SDL_BUTTON_LEFT ] = 0 ;
}
}
}
static void draw ( void )
{
HubMission * mission ;
blitRectScaled ( atlasTexture - > texture , 0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT , & worldMap - > rect , 0 ) ;
2018-01-24 08:16:52 +01:00
for ( mission = hubMissionHead . next ; mission ! = NULL ; mission = mission - > next )
{
2018-02-16 23:50:55 +01:00
switch ( mission - > status )
2018-01-24 08:16:52 +01:00
{
2018-02-16 23:50:55 +01:00
case MS_INCOMPLETE :
SDL_SetTextureColorMod ( atlasTexture - > texture , 255 , 0 , 0 ) ;
blitRectScaled ( atlasTexture - > texture , mission - > x , mission - > y , blipSize , blipSize , & alert - > rect , 1 ) ;
drawText ( mission - > x , mission - > y - 32 , 18 , TA_CENTER , colors . white , mission - > name ) ;
break ;
case MS_PARTIAL :
case MS_MISSING_HEART_CELL :
SDL_SetTextureColorMod ( atlasTexture - > texture , 255 , 255 , 0 ) ;
blitRectScaled ( atlasTexture - > texture , mission - > x , mission - > y , blipSize , blipSize , & alert - > rect , 1 ) ;
drawText ( mission - > x , mission - > y - 32 , 18 , TA_CENTER , colors . white , mission - > name ) ;
break ;
2018-01-24 08:16:52 +01:00
}
}
2018-02-16 23:50:55 +01:00
SDL_SetTextureColorMod ( atlasTexture - > texture , 255 , 255 , 255 ) ;
drawRect ( 0 , 0 , SCREEN_WIDTH , 32 , 0 , 0 , 0 , 192 ) ;
drawText ( 10 , 5 , 18 , TA_LEFT , colors . white , " Missions : %d / %d " , completedMissions , numMissions ) ;
drawText ( 210 , 5 , 18 , TA_LEFT , colors . white , " MIAs : %d / %d " , 0 , game . totalMIAs ) ;
drawText ( 410 , 5 , 18 , TA_LEFT , colors . white , " Targets : %d / %d " , 0 , game . totalTargets ) ;
drawText ( 610 , 5 , 18 , TA_LEFT , colors . white , " Keys : %d / %d " , 0 , game . totalKeys ) ;
drawText ( 810 , 5 , 18 , TA_LEFT , colors . white , " Hearts : %d / %d " , 0 , game . totalHearts ) ;
drawText ( 1010 , 5 , 18 , TA_LEFT , colors . white , " Cells : %d / %d " , 0 , game . totalCells ) ;
2018-01-24 08:16:52 +01:00
}
static int getMissionStatus ( char * id )
{
Tuple * t ;
for ( t = game . missionStatusHead . next ; t ! = NULL ; t = t - > next )
{
if ( strcmp ( t - > key , id ) = = 0 )
{
return t - > value . i ;
}
}
2018-01-28 17:14:17 +01:00
return MS_LOCKED ;
2018-01-24 08:16:52 +01:00
}
static void unlockMission ( char * id )
{
Tuple * t ;
for ( t = game . missionStatusHead . next ; t ! = NULL ; t = t - > next )
{
if ( strcmp ( t - > key , id ) = = 0 )
{
2018-01-28 17:14:17 +01:00
if ( t - > value . i = = MS_LOCKED )
2018-01-24 08:16:52 +01:00
{
t - > value . i = MS_INCOMPLETE ;
2018-01-28 17:14:17 +01:00
SDL_LogMessage ( SDL_LOG_CATEGORY_APPLICATION , SDL_LOG_PRIORITY_DEBUG , " Unlocked mission %s " , id ) ;
2018-01-24 08:16:52 +01:00
}
2018-01-28 17:14:17 +01:00
2018-01-24 08:16:52 +01:00
return ;
}
}
t = malloc ( sizeof ( Tuple ) ) ;
memset ( t , 0 , sizeof ( Tuple ) ) ;
game . missionStatusTail - > next = t ;
game . missionStatusTail = t ;
STRNCPY ( t - > key , id , MAX_NAME_LENGTH ) ;
t - > value . i = MS_INCOMPLETE ;
2018-01-28 17:14:17 +01:00
SDL_LogMessage ( SDL_LOG_CATEGORY_APPLICATION , SDL_LOG_PRIORITY_DEBUG , " Unlocked mission %s " , id ) ;
2018-01-24 08:16:52 +01:00
}
static void unlockAllLevels ( void )
{
HubMission * mission ;
for ( mission = hubMissionHead . next ; mission ! = NULL ; mission = mission - > next )
{
2018-01-28 17:14:17 +01:00
if ( mission - > status = = MS_LOCKED | | mission - > status = = MS_INCOMPLETE )
2018-01-24 08:16:52 +01:00
{
mission - > status = MS_INCOMPLETE ;
unlockMission ( mission - > id ) ;
}
}
}
static void unlockNeighbouringMission ( HubMission * sourceMission )
{
2018-02-16 23:50:55 +01:00
HubMission * mission , * missions [ numMissions ] ;
2018-01-24 08:16:52 +01:00
int i ;
i = 0 ;
2018-02-16 23:50:55 +01:00
memset ( missions , 0 , sizeof ( HubMission * ) * numMissions ) ;
2018-01-24 08:16:52 +01:00
for ( mission = hubMissionHead . next ; mission ! = NULL ; mission = mission - > next )
{
mission - > distance = 99999 ;
if ( mission - > status = = MS_COMPLETE | | mission - > status = = MS_MISSING_HEART_CELL | | mission - > status = = MS_PARTIAL )
{
continue ;
}
mission - > distance = getDistance ( mission - > x , mission - > y , sourceMission - > x , sourceMission - > y ) ;
missions [ i + + ] = mission ;
}
qsort ( missions , i , sizeof ( HubMission * ) , missionComparator ) ;
mission = missions [ 0 ] ;
if ( mission ! = NULL )
{
2018-01-28 17:14:17 +01:00
if ( mission - > status = = MS_LOCKED | | mission - > status = = MS_INCOMPLETE )
2018-01-24 08:16:52 +01:00
{
mission - > status = MS_INCOMPLETE ;
unlockMission ( mission - > id ) ;
}
mission = missions [ 1 ] ;
if ( mission ! = NULL )
{
2018-01-28 17:14:17 +01:00
if ( mission - > status = = MS_LOCKED | | mission - > status = = MS_INCOMPLETE )
2018-01-24 08:16:52 +01:00
{
mission - > status = MS_INCOMPLETE ;
unlockMission ( mission - > id ) ;
}
}
}
}
2018-02-16 23:50:55 +01:00
HubMission * getMissionAt ( int x , int y )
2018-01-24 08:16:52 +01:00
{
HubMission * rtn ;
HubMission * mission ;
float distance , dist ;
rtn = NULL ;
distance = 32 ;
for ( mission = hubMissionHead . next ; mission ! = NULL ; mission = mission - > next )
{
2018-02-16 23:50:55 +01:00
if ( mission - > status = = MS_INCOMPLETE | | mission - > status = = MS_MISSING_HEART_CELL | | mission - > status = = MS_PARTIAL )
2018-01-24 08:16:52 +01:00
{
2018-02-16 23:50:55 +01:00
dist = getDistance ( x , y , mission - > x , mission - > y ) ;
if ( dist < distance )
{
rtn = mission ;
distance = dist ;
}
2018-01-24 08:16:52 +01:00
}
}
return rtn ;
}
2018-02-16 23:50:55 +01:00
static void loadMissions ( void )
{
cJSON * root , * node ;
char * text ;
HubMission * mission ;
double ratioX , ratioY ;
/* the original Attrition is based on 800x600, so multiply up */
ratioX = SCREEN_WIDTH / 800.0 ;
ratioY = SCREEN_HEIGHT / 600.0 ;
text = readFile ( " data/hub/missions.json " ) ;
root = cJSON_Parse ( text ) ;
for ( node = cJSON_GetObjectItem ( root , " missions " ) - > child ; node ! = NULL ; node = node - > next )
{
mission = malloc ( sizeof ( HubMission ) ) ;
memset ( mission , 0 , sizeof ( HubMission ) ) ;
hubMissionTail - > next = mission ;
hubMissionTail = mission ;
STRNCPY ( mission - > id , cJSON_GetObjectItem ( node , " id " ) - > valuestring , MAX_NAME_LENGTH ) ;
STRNCPY ( mission - > name , cJSON_GetObjectItem ( node , " name " ) - > valuestring , MAX_NAME_LENGTH ) ;
STRNCPY ( mission - > description , cJSON_GetObjectItem ( node , " description " ) - > valuestring , MAX_DESCRIPTION_LENGTH ) ;
mission - > status = MS_LOCKED ;
mission - > unlockCount = cJSON_GetObjectItem ( node , " unlockCount " ) - > valueint ;
mission - > x = cJSON_GetObjectItem ( node , " x " ) - > valuedouble * ratioX ;
mission - > y = cJSON_GetObjectItem ( node , " y " ) - > valuedouble * ratioY ;
}
cJSON_Delete ( root ) ;
free ( text ) ;
}
2018-01-24 08:16:52 +01:00
static int missionComparator ( const void * a , const void * b )
{
HubMission * m1 = * ( ( HubMission * * ) a ) ;
HubMission * m2 = * ( ( HubMission * * ) b ) ;
return m2 - > distance - m1 - > distance ;
}
2018-02-16 23:50:55 +01:00
void destroyHub ( void )
{
}