//------------------------------------------------- // File: ggsm_arcade_entity.sch // Purpose: general functions required by system //------------------------------------------------- //------------------------------------------------- // INCLUDES //------------------------------------------------- USING "ggsm_structs.sch" USING "ggsm_maths.sch" USING "ggsm_data.sch" USING "ggsm_helpers.sch" //------------------------------------------------- // DEPTH SORTING FUNCTIONS //------------------------------------------------- /// PURPOSE: /// Reset Z Sort Array /// PARAMS: /// sArray - PROC GGSM_RESET_ENTITY_DEPTHSORT_ARRAY() INT i REPEAT GGSM_MAX_ENTITIES i sGGSMData.sZSortData[i].iEntityIndex = GGSM_INVALID_ENTITY sGGSMData.sZSortData[i].iZDepth = -1 ENDREPEAT ENDPROC /// PURPOSE: /// Sort Z Sort Array /// PARAMS: /// sArray - Array to sort /// iLeft - left index /// iRight - right index PROC GGSM_QUICK_SORT_ZDEPTH_ARRAY(GGSM_ZSORTDATA &sArray[], INT iLeft, INT iRight) INT i, j INT p = sArray[((iLeft + iRight) / 2)].iZDepth GGSM_ZSORTDATA q i = iLeft j = iRight WHILE (i <= j) WHILE ((sArray[i].iZDepth > p) AND (i < iRight)) i++ ENDWHILE WHILE ((p > sArray[j].iZDepth) AND (j > iLeft)) j-- ENDWHILE IF (i <= j) q = sArray[i] sArray[i] = sArray[j] sArray[j] = q i++ j-- ENDIF ENDWHILE IF (i < iRight) GGSM_QUICK_SORT_ZDEPTH_ARRAY(sArray, i, iRight) ENDIF IF (iLeft < j) GGSM_QUICK_SORT_ZDEPTH_ARRAY(sArray, iLeft, j) ENDIF ENDPROC //------------------------------------------------- // ENTITY FUNCTIONS //------------------------------------------------- /// PURPOSE: /// Sets Z Depth for zsorting /// PARAMS: /// ent - /// iZDepth - PROC GGSM_ENTITY_SET_Z_DEPTH(GGSM_ENTITY &ent, INT iZDepth) INT i SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_FORCE_Z_SORT) REPEAT GGSM_MAX_ENTITIES i IF (sGGSMData.sZSortData[i].iEntityIndex = GGSM_ENTITY_GET_ARRAY_INDEX(ent)) sGGSMData.sZSortData[i].iZDepth = iZDepth EXIT ENDIF ENDREPEAT REPEAT GGSM_MAX_ENTITIES i IF (sGGSMData.sZSortData[i].iEntityIndex = GGSM_INVALID_ENTITY) sGGSMData.sZSortData[i].iZDepth = iZDepth sGGSMData.sZSortData[i].iEntityIndex = GGSM_ENTITY_GET_ARRAY_INDEX(ent) EXIT ENDIF ENDREPEAT ENDPROC PROC GGSM_ENTITY_CLEAR_Z_DEPTH(GGSM_ENTITY &ent) INT i REPEAT GGSM_MAX_ENTITIES i IF (sGGSMData.sZSortData[i].iEntityIndex = GGSM_ENTITY_GET_ARRAY_INDEX(ent)) sGGSMData.sZSortData[i].iEntityIndex = GGSM_INVALID_ENTITY sGGSMData.sZSortData[i].iZDepth = -1 SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_FORCE_Z_SORT) ENDIF ENDREPEAT ENDPROC PROC GGSM_ENTITY_SET_PATH_INDEX(GGSM_ENTITY &ent, INT i) ent.iPathNumber = i ENDPROC PROC GGSM_ENTITY_RESET_BASE_SPEED(GGSM_ENTITY &ent) GGSM_ENTITY_DATA dat = GGSM_ENTITY_DATA_GET(ent.eType) ent.fSpeed = dat.fBaseSpeed ENDPROC PROC GGSM_ENTITY_SCALE_BASE_SPEED(GGSM_ENTITY &ent, FLOAT fScale) GGSM_ENTITY_DATA dat = GGSM_ENTITY_DATA_GET(ent.eType) ent.fSpeed = (dat.fBaseSpeed * fScale) ENDPROC /// PURPOSE: /// Gets the speed multiplied by timescale /// PARAMS: /// ent - /// RETURNS: /// FUNC FLOAT GGSM_ENTITY_GET_SPEED(GGSM_ENTITY &ent) IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_IS_PLAYER_ALLIED) RETURN ent.fSpeed ENDIF RETURN ent.fSpeed * sGGSMData.fTimeScale ENDFUNC PROC GGSM_ENTITY_SET_PACKED_ORIGIN(GGSM_ENTITY &ent, VECTOR_2D vec) ent.iPackedLocalOrigin = GGSM_PACK_VECTOR_2D_TO_INT(vec) ENDPROC FUNC VECTOR_2D GGSM_GET_RANDOM_POINT_ON_ENTITY(GGSM_ENTITY &ent) GGSM_ENTITY_DATA entData = GGSM_ENTITY_DATA_GET(ent.eType) VECTOR_2D size = GGSM_GET_SPRITE_SIZE(entData.eSpriteType) VECTOR_2D pos = ent.sWorld.vPosition size.x /= 2.0 size.y /= 2.0 pos.x += GET_RANDOM_FLOAT_IN_RANGE(-size.x, size.x) pos.y += GET_RANDOM_FLOAT_IN_RANGE(-size.y, size.y) RETURN pos ENDFUNC FUNC BOOL GGSM_ENTITY_IS_MOVEMENT_COMPLETE(GGSM_ENTITY &ent) IF (ent.eMoveType = GGSM_MOVEMENT_NONE) RETURN TRUE ENDIF RETURN IS_BITMASK_ENUM_AS_ENUM_SET(ent.eMoveFlags, GGSM_MOVE_BIT_COMPLETE) ENDFUNC //------------------------------------------------- // ENTITY ARRAY FUNCTIONS //------------------------------------------------- /// PURPOSE: /// Counts # of entities free in array /// PARAMS: /// array - /// RETURNS: /// FUNC INT GGSM_COUNT_FREE_ENTITIES(GGSM_ENTITY &array[]) INT i INT cnt = 0 REPEAT COUNT_OF(array) i IF (array[i].eState = GGSM_ENTITY_STATE_NONE) cnt ++ ENDIF ENDREPEAT RETURN cnt ENDFUNC /// PURPOSE: /// Gets the next free entity index /// PARAMS: /// array - entity array /// ind - Index of the next free index /// iSearchIndex - Index to start searching from /// RETURNS: /// TRUE if entity can be found FUNC BOOL GGSM_GET_FREE_ENTITY(GGSM_ENTITY &array[], INT &ind, INT &iSearchIndex) INT i INT cnt = COUNT_OF(array) // stops any overflow nonsense iSearchIndex = ABSI(iSearchIndex) % cnt ind = GGSM_INVALID_ENTITY REPEAT cnt i IF (array[iSearchIndex].eState = GGSM_ENTITY_STATE_NONE) ind = iSearchIndex RETURN TRUE ENDIF iSearchIndex = (iSearchIndex + 1) % cnt ENDREPEAT RETURN FALSE ENDFUNC /// PURPOSE: /// Gets a number of free entity /// PARAMS: /// array - array of entity /// iNumProjectiles - # of desired entity /// iArray - Array of ints with entity indexes in /// iSearchIndex - Index in array to search for /// RETURNS: /// # of entity it could get FUNC INT GGSM_GET_FREE_ENTITIES(GGSM_ENTITY &array[], INT iNumEntities, INT &iArray[], INT &iSearchIndex) INT i INT iEntitiesFound INT cnt = COUNT_OF(array) // stops any overflow nonsense iSearchIndex = ABSI(iSearchIndex) % cnt REPEAT cnt i IF (array[iSearchIndex].eState = GGSM_ENTITY_STATE_NONE) iArray[iEntitiesFound] = iSearchIndex iEntitiesFound ++ ENDIF iSearchIndex = (iSearchIndex + 1) % cnt IF (iNumEntities = iEntitiesFound) OR (iEntitiesFound = COUNT_OF(iArray)) RETURN iEntitiesFound ENDIF ENDREPEAT RETURN iEntitiesFound ENDFUNC /// PURPOSE: /// Gets the index of the closest entity to a position /// PARAMS: /// array - array /// vPos - position to check /// RETURNS: /// FUNC INT GGSM_GET_CLOSEST_ENTITY_INDEX(GGSM_ENTITY &array[], VECTOR_2D vPos) INT i INT ind = GGSM_INVALID_ENTITY FLOAT fDist FLOAT fMaxDist = MAX_FLOAT REPEAT COUNT_OF(array) i IF (array[i].eState = GGSM_ENTITY_STATE_ALIVE) fDist = VECTOR_2D_DIST2(array[i].sWorld.vPosition, vPos) IF (fDist < fMaxDist) fMaxDist = fDist ind = i ENDIF ENDIF ENDREPEAT RETURN ind ENDFUNC /// PURPOSE: /// Gets the index of the closest entity to a position /// PARAMS: /// array - array /// vPos - position to check /// RETURNS: /// FUNC INT GGSM_GET_CLOSEST_ENEMY_ENTITY_INDEX(GGSM_ENTITY &array[], VECTOR_2D vPos, BOOL bAllied) INT i INT ind = GGSM_INVALID_ENTITY FLOAT fDist FLOAT fMaxDist = MAX_FLOAT REPEAT COUNT_OF(array) i IF (array[i].eState = GGSM_ENTITY_STATE_ALIVE) AND (IS_BITMASK_ENUM_AS_ENUM_SET(array[i].eFlags, GGSM_ENTITY_BIT_IS_PLAYER_ALLIED) != bAllied) IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(array[i].eFlags, GGSM_ENTITY_BIT_NO_COLLISION) fDist = VECTOR_2D_DIST2(array[i].sCollider.sAABB.vCenter, vPos) IF (fDist < fMaxDist) fMaxDist = fDist ind = i ENDIF ENDIF ENDIF ENDREPEAT RETURN ind ENDFUNC //------------------------------------------------- // ENTITY GROUP FUNCTIONS //------------------------------------------------- /// PURPOSE: /// Resets Entity Group /// PARAMS: /// group - PROC GGSM_RESET_ENTITY_GROUP(GGSM_ENTITY_GROUP &group) group.eFlags = GGSM_GROUP_BIT_NONE group.iLeader = GGSM_INVALID_ENTITY group.iMemberBitSet = 0 group.iMembersToCreate = 0 group.iFormSpawnBitSet = 0 group.iMembersOnStageBitSet = 0 group.iActiveCount = 0 group.fDistCounter = 0.0 GGSM_FORMATION_SET_TYPE(group.sFormSettings, GGSM_FORMATION_NONE) ENDPROC /// PURPOSE: /// Checks if group is running /// PARAMS: /// group - /// RETURNS: /// FUNC BOOL GGSM_ENTITY_GROUP_IS_RUNNING(GGSM_ENTITY_GROUP &group) RETURN IS_BITMASK_ENUM_AS_ENUM_SET(group.eFlags, GGSM_GROUP_BIT_ACTIVE) ENDFUNC /// PURPOSE: /// Checks if group has finished (all members are dead) /// PARAMS: /// group - /// RETURNS: /// FUNC BOOL GGSM_ENTITY_GROUP_HAS_GROUP_FINISHED(GGSM_ENTITY_GROUP &group) IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(group.eFlags, GGSM_GROUP_BIT_ACTIVE) RETURN TRUE ENDIF RETURN (group.iMembersToCreate = 0) AND (group.iActiveCount = 0) ENDFUNC PROC GGSM_DEACTIVATE_ENTITY_GROUP(GGSM_ENTITY_GROUP &group) #IF IS_DEBUG_BUILD CDEBUG1LN(DEBUG_MINIGAME, "GGSM_DEACTIVATE_ENTITY_GROUP - GROUP:", group.iGroupID) #ENDIF GGSM_RESET_ENTITY_GROUP(group) ENDPROC PROC GGSM_SET_ENTITY_GROUP_FLAGS(GGSM_ENTITY_GROUP &group, GGSM_GROUP_BIT eFlags) SET_BITMASK_ENUM_AS_ENUM(group.eFlags, eFlags) ENDPROC /// PURPOSE: /// Activates and entity group /// PARAMS: /// group - group /// iFlags - flags entity to create /// iMembersLeftToCreate - PROC GGSM_ACTIVATE_ENTITY_GROUP(GGSM_ENTITY_GROUP &group, GGSM_GROUP_BIT eFlags = GGSM_GROUP_BIT_NONE, INT iMembersLeftToCreate = 0) GGSM_RESET_ENTITY_GROUP(group) group.eFlags = eFlags group.iMembersToCreate = iMembersLeftToCreate SET_BITMASK_ENUM_AS_ENUM(group.eFlags, GGSM_GROUP_BIT_ACTIVE) ENDPROC /// PURPOSE: /// Activates groups as formation /// PARAMS: /// group - /// eSettings - PROC GGSM_ACTIVATE_ENTITY_GROUP_AS_FORMATION(GGSM_ENTITY_GROUP &group, GGSM_FORMATION_DATA &eSettings) GGSM_ENTITY_TYPE entType = GGSM_FORMATION_GET_ENTITY_TYPE(group.sFormSettings) GGSM_ENTITY_DATA entData = GGSM_ENTITY_DATA_GET(entType) VECTOR_2D spriteSize = GGSM_GET_SPRITE_SIZE(entData.eSpriteType) GGSM_RESET_ENTITY_GROUP(group) group.sFormSettings = eSettings group.iMembersToCreate = eSettings.iFormationMembers group.fDistCounter = FMAX(ABSF(spriteSize.x), ABSF(spriteSize.y)) * 1.5 SET_BITMASK_ENUM_AS_ENUM(group.eFlags, GGSM_GROUP_BIT_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(group.eFlags, GGSM_GROUP_BIT_IS_FORMATION) SET_BITMASK_ENUM_AS_ENUM(group.eFlags, GGSM_GROUP_BIT_END_WHEN_ALL_OFFSCREEN) #IF IS_DEBUG_BUILD CDEBUG1LN(DEBUG_MINIGAME, "GGSM_ACTIVATE_ENTITY_GROUP_AS_FORMATION - GROUP:", group.iGroupID, " TYPE:", GGSM_FORMATION_TYPE_TO_STRING(GGSM_FORMATION_GET_TYPE(group.sFormSettings)), " MOVE PATTERN:", GGSM_MOVEMENT_TYPE_TO_STRING(GGSM_FORMATION_GET_MOVEMENT_TYPE(group.sFormSettings)), " #:", GGSM_FORMATION_GET_MEMBER_COUNT(group.sFormSettings)) #ENDIF ENDPROC /// PURPOSE: /// Resets a group array /// PARAMS: /// array - PROC GGSM_RESET_ENTITY_GROUP_ARRAY(GGSM_ENTITY_GROUP &array[]) INT i REPEAT COUNT_OF(array) i array[i].iGroupID = i GGSM_RESET_ENTITY_GROUP(array[i]) ENDREPEAT ENDPROC /// PURPOSE: /// Searchs for a free entity group /// PARAMS: /// array - /// RETURNS: /// Index into group array - if no free group this returns -1 FUNC INT GGSM_GET_FREE_ENTITY_GROUP(GGSM_ENTITY_GROUP &array[]) INT i REPEAT COUNT_OF(array) i IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(array[i].eFlags, GGSM_GROUP_BIT_ACTIVE) RETURN i ENDIF ENDREPEAT RETURN GGSM_INVALID_GROUP_ID ENDFUNC /// PURPOSE: /// Adds an Entity to a group /// PARAMS: /// ent - entity to add /// iGroupID - group id to add to PROC GGSM_ADD_ENTITY_TO_GROUP(GGSM_ENTITY &ent, INT iGroupID) INT iArrayIndex = GGSM_ENTITY_GET_ARRAY_INDEX(ent) IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntityGroup[iGroupID].eFlags, GGSM_GROUP_BIT_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntityGroup[iGroupID].eFlags, GGSM_GROUP_BIT_ACTIVE) ENDIF IF (sGGSMData.sEntityGroup[iGroupID].iLeader = GGSM_INVALID_ENTITY) sGGSMData.sEntityGroup[iGroupID].iLeader = iArrayIndex ENDIF IF NOT IS_BIT_SET(sGGSMData.sEntityGroup[iGroupID].iMemberBitSet, iArrayIndex) SET_BIT(sGGSMData.sEntityGroup[iGroupID].iMemberBitSet, iArrayIndex) SET_BIT(sGGSMData.sEntityGroup[iGroupID].iMembersOnStageBitSet, iArrayIndex) sGGSMData.sEntityGroup[iGroupID].iActiveCount ++ sGGSMData.sEntityGroup[iGroupID].iMembersToCreate -- IF (sGGSMData.sEntityGroup[iGroupID].iMembersToCreate < 0) sGGSMData.sEntityGroup[iGroupID].iMembersToCreate = 0 ENDIF ENDIF IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntityGroup[iGroupID].eFlags, GGSM_GROUP_BIT_END_WHEN_ALL_OFFSCREEN) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_REMOVE_WHEN_OFFSCREEN) ENDIF CPRINTLN(DEBUG_MINIGAME, "GGSM_ADD_ENTITY_TO_GROUP #", iGroupID, " - TYPE:", GGSM_ENTITY_TYPE_TO_STRING(ent.eType), " ARRAY INDEX:", iArrayIndex) GGSM_ENTITY_SET_GROUP_ID(ent, iGroupID) ENDPROC /// PURPOSE: /// Removes entity from a group - This will shutdown the group if there are no members left /// PARAMS: /// ent - PROC GGSM_REMOVE_ENTITY_FROM_GROUP(GGSM_ENTITY &ent) INT grp = GGSM_ENTITY_GET_GROUP_ID(ent) IF (grp = GGSM_INVALID_GROUP_ID) EXIT ENDIF INT iArrayIndex = GGSM_ENTITY_GET_ARRAY_INDEX(ent) IF IS_BIT_SET(sGGSMData.sEntityGroup[grp].iMemberBitSet, iArrayIndex) CLEAR_BIT(sGGSMData.sEntityGroup[grp].iMemberBitSet, iArrayIndex) CLEAR_BIT(sGGSMData.sEntityGroup[grp].iMembersOnStageBitSet, iArrayIndex) sGGSMData.sEntityGroup[grp].iActiveCount -- ENDIF CPRINTLN(DEBUG_MINIGAME, "GGSM_REMOVE_ENTITY_FROM_GROUP #", grp, " - TYPE:", GGSM_ENTITY_TYPE_TO_STRING(ent.eType), " ARRAY INDEX:", iArrayIndex) GGSM_ENTITY_SET_GROUP_ID(ent, GGSM_INVALID_GROUP_ID) IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntityGroup[grp].eFlags, GGSM_GROUP_BIT_IS_FORMATION) IF (sGGSMData.sEntityGroup[grp].iActiveCount = 0) GGSM_DEACTIVATE_ENTITY_GROUP(sGGSMData.sEntityGroup[grp]) ENDIF ELIF (sGGSMData.sEntityGroup[grp].iMembersToCreate = 0) IF (sGGSMData.sEntityGroup[grp].iActiveCount = 0) GGSM_DEACTIVATE_ENTITY_GROUP(sGGSMData.sEntityGroup[grp]) ENDIF ENDIF ENDPROC //------------------------------------------------- // QUERY FUNCTION //------------------------------------------------- FUNC BOOL GGSM_DOES_PLAYER_SHIP_EXIST() IF (sGGSMData.iPlayerShipIndex = GGSM_INVALID_ENTITY) RETURN FALSE ENDIF RETURN (sGGSMData.sEntities[sGGSMData.iPlayerShipIndex].eState != GGSM_ENTITY_STATE_NONE) ENDFUNC FUNC BOOL GGSM_IS_PLAYER_SHIP_ALIVE() IF (sGGSMData.iPlayerShipIndex = GGSM_INVALID_ENTITY) RETURN FALSE ENDIF RETURN (sGGSMData.sEntities[sGGSMData.iPlayerShipIndex].eState = GGSM_ENTITY_STATE_ALIVE) ENDFUNC FUNC BOOL GGSM_DOES_PLAYER_DECOY_EXIST() IF (sGGSMData.iPlayerDecoyIndex = GGSM_INVALID_ENTITY) RETURN FALSE ENDIF RETURN (sGGSMData.sEntities[sGGSMData.iPlayerDecoyIndex].eState != GGSM_ENTITY_STATE_NONE) ENDFUNC FUNC BOOL GGSM_DOES_PLAYER_SHIELD_EXIST() IF (sGGSMData.iPlayerShieldIndex = GGSM_INVALID_ENTITY) RETURN FALSE ENDIF RETURN (sGGSMData.sEntities[sGGSMData.iPlayerShieldIndex].eState != GGSM_ENTITY_STATE_NONE) ENDFUNC FUNC BOOL GGSM_IS_PLAYER_TOTALLY_DEFEATED() IF GGSM_DOES_PLAYER_SHIP_EXIST() RETURN FALSE ENDIF RETURN (sGGSMData.iPlayerLives = 0) ENDFUNC PROC GGSM_SET_PLAYER_INVUNERABLE() IF GGSM_DOES_PLAYER_SHIP_EXIST() sGGSMData.sEntities[sGGSMData.iPlayerShipIndex].iInvTimeMS = GET_GAME_TIMER() + GGSM_PLAYER_INITIAL_INV_TIME ENDIF ENDPROC //------------------------------------------------- // PROJECTILE ARRAY FUNCTIONS //------------------------------------------------- /// PURPOSE: /// Sets all projectiles to be inactive /// PARAMS: /// array - array of projectiles PROC GGSM_RESET_PROJECTILE_ARRAY(GGSM_PROJECTILE &array[]) INT i INT cnt = COUNT_OF(array) REPEAT cnt i array[i].eFlags = GGSM_PROJECTILE_BIT_NONE array[i].fTimer = 0 ENDREPEAT ENDPROC /// PURPOSE: /// Gets the next free projectile index /// PARAMS: /// array - projecile array /// ind - Index of the next free index /// iSearchIndex - Index to start searching from /// RETURNS: /// TRUE if projectile can be found FUNC BOOL GGSM_GET_FREE_PROJECTILE(GGSM_PROJECTILE &array[], INT &ind, INT &iSearchIndex) INT i INT cnt = COUNT_OF(array) // stops any overflow nonsense iSearchIndex = ABSI(iSearchIndex) % cnt ind = GGSM_INVALID_PROJECTILE REPEAT cnt i IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(array[iSearchIndex].eFlags, GGSM_PROJECTILE_BIT_ACTIVE) ind = iSearchIndex RETURN TRUE ENDIF iSearchIndex = (iSearchIndex + 1) % cnt ENDREPEAT RETURN FALSE ENDFUNC /// PURPOSE: /// Gets a number of free projectiles /// PARAMS: /// array - array of projectiles /// iNumProjectiles - # of desired projectiles /// iArray - Array of ints with projectile indexes in /// iSearchIndex - Index in array to search for /// RETURNS: /// # of projectiles it could get FUNC INT GGSM_GET_FREE_PROJECTILES(GGSM_PROJECTILE &array[], INT iNumProjectiles, INT &iArray[], INT &iSearchIndex) INT i INT iProjectilesFound INT cnt = COUNT_OF(array) // stops any overflow nonsense iSearchIndex = ABSI(iSearchIndex) % cnt REPEAT cnt i IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(array[iSearchIndex].eFlags, GGSM_PROJECTILE_BIT_ACTIVE) iArray[iProjectilesFound] = iSearchIndex iProjectilesFound ++ ENDIF iSearchIndex = (iSearchIndex + 1) % cnt IF (iProjectilesFound = iNumProjectiles) OR (iProjectilesFound = cnt) RETURN iProjectilesFound ENDIF ENDREPEAT RETURN 0 ENDFUNC //------------------------------------------------- // PROJECTILE FUNCTIONS //------------------------------------------------- FUNC VECTOR_2D GGSM_GET_TARGET_AT_PLAYER_POSITION() IF (sGGSMData.iPlayerDecoyIndex != GGSM_INVALID_ENTITY) RETURN sGGSMData.sEntities[sGGSMData.iPlayerDecoyIndex].sWorld.vPosition ENDIF IF (sGGSMData.iPlayerShipIndex != GGSM_INVALID_ENTITY) RETURN sGGSMData.sEntities[sGGSMData.iPlayerShipIndex].sWorld.vPosition ENDIF RETURN INIT_VECTOR_2D(0, 0) ENDFUNC FUNC INT GGSM_PROJECTILE_GET_TARGET_INDEX(GGSM_PROJECTILE &ent) RETURN ent.iTargetIndex ENDFUNC PROC GGSM_PROJECTILE_SET_TARGET_INDEX(GGSM_PROJECTILE &ent, INT i) ent.iTargetIndex = i ENDPROC FUNC BOOL GGSM_PROJECTILE_HAS_COLLISION(GGSM_PROJECTILE &ent) IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_PROJECTILE_BIT_ACTIVE) RETURN FALSE ENDIF IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_PROJECTILE_BIT_HAS_NO_COLLISION) RETURN FALSE ENDIF RETURN TRUE ENDFUNC /// PURPOSE: /// Initializes projectile based on data /// PARAMS: /// ent - projectile to initialize /// eType - projectile type /// vPos - world position of projectile /// fRot - world rotation of projectile PROC GGSM_PROJECTILE_INIT(GGSM_PROJECTILE &ent, GGSM_PROJECTILE_TYPE eType, VECTOR_2D vPos, FLOAT fRot, BOOL bIsFriendly = FALSE) GGSM_PROJECTILE_DATA dat = GGSM_PROJECTILE_DATA_GET(eType) VECTOR_2D dir ent.eFlags = GGSM_PROJECTILE_BIT_NONE ent.eType = eType ent.fTimer = 0.0 ent.fDistTravelled = 0 ent.fLength = dat.fLength ent.fSpeed = dat.fBaseSpeed ent.sCollider.sData.fColRadius = dat.fRadius ent.vDirection = GGSM_GET_VECTOR_FROM_HEADING(fRot) ent.iPackedOrigin = GGSM_PACK_VECTOR_2D_TO_INT(vPos) ent.iTargetIndex = GGSM_INVALID_ENTITY IF (ent.fLength = 0.0) ent.sCollider.sData.eType = GGSM_COLLISION_CIRCLE ent.sCollider.sData.vCollisionVectors[0] = vPos ent.sCollider.sData.vCollisionVectors[1] = vPos ELSE dir.x = ent.vDirection.x * ent.fLength dir.y = ent.vDirection.y * ent.fLength ent.sCollider.sData.eType = GGSM_COLLISION_CAPSULE ent.sCollider.sData.vCollisionVectors[0] = vPos ent.sCollider.sData.vCollisionVectors[1].x = vPos.x + dir.x ent.sCollider.sData.vCollisionVectors[1].y = vPos.y + dir.y ENDIF SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_PROJECTILE_BIT_ACTIVE) GGSM_COLLIDER_CALCULATE_AABB(ent.sCollider) IF (bIsFriendly) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_PROJECTILE_BIT_IS_PLAYER_ALLIED) ENDIF IF (eType = GGSM_PROJECTILE_HOMING_ROCKET) ent.iTargetIndex = GGSM_GET_CLOSEST_ENEMY_ENTITY_INDEX(sGGSMData.sEntities, vPos, bIsFriendly) IF (ent.iTargetIndex != GGSM_INVALID_ENTITY) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_PROJECTILE_BIT_IS_HOMING) ENDIF ENDIF IF (eType = GGSM_PROJECTILE_ENEMY_CLUSTER_BOMB) OR (eType = GGSM_PROJECTILE_DANK_CLUSTERBOMB) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_PROJECTILE_BIT_IS_CLUSTER_BOMB) ELIF (eType = GGSM_PROJECTILE_ENEMY_BEAM) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_PROJECTILE_BIT_LOCKED_TO_PARENT) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_PROJECTILE_BIT_BEAM_WEAPON) ELIF (eType = GGSM_PROJECTILE_DANK_HOMING_ROCKET) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_PROJECTILE_BIT_IS_DELAYED_HOMING) ENDIF ENDPROC PROC GGSM_PROJECTILE_CREATE_ENEMY_RADIAL_SPREAD(GGSM_PROJECTILE_TYPE eType, VECTOR_2D vPos, INT iCount, FLOAT fRot = 0.0, BOOL bTargetPlayer = FALSE) INT ind, cnt INT iProjList[16] FLOAT fAngle = fRot FLOAT fAngDiff = 360.0 / TO_FLOAT(iCount) VECTOR_2D vec cnt = GGSM_GET_FREE_PROJECTILES(sGGSMData.sProjectiles, iCount, iProjList, sGGSMData.iProjectileSearchIndex) IF (cnt = 0) EXIT ENDIF IF (bTargetPlayer) vec = SUBTRACT_VECTOR_2D(GGSM_GET_TARGET_AT_PLAYER_POSITION(), vPos) fAngle = GET_HEADING_FROM_VECTOR_2D(vec.x, vec.y) ENDIF REPEAT cnt ind GGSM_PROJECTILE_INIT(sGGSMData.sProjectiles[iProjList[ind]], eType, vPos, fAngle, FALSE) fAngle += fAngDiff ENDREPEAT GGSM_PROJECTILE_DATA dat = GGSM_PROJECTILE_DATA_GET(eType) GGSM_PLAY_SOUND_FROM_POSITION(dat.eProjSound, vPos) ENDPROC PROC GGSM_PROJECTILE_CREATE_ENEMY_CONE_SPREAD(GGSM_PROJECTILE_TYPE eType, VECTOR_2D vPos, FLOAT fSpreadAngle, INT iCount, BOOL bTargetPlayer = FALSE) INT ind, cnt INT iProjList[16] FLOAT fBaseAngle, fAngle FLOAT fAngDiff = 360.0 / TO_FLOAT(iCount) VECTOR_2D vec cnt = GGSM_GET_FREE_PROJECTILES(sGGSMData.sProjectiles, iCount, iProjList, sGGSMData.iProjectileSearchIndex) IF (cnt = 0) EXIT ENDIF IF (bTargetPlayer) vec = SUBTRACT_VECTOR_2D(GGSM_GET_TARGET_AT_PLAYER_POSITION(), vPos) fBaseAngle = GET_HEADING_FROM_VECTOR_2D(vec.x, vec.y) ENDIF fAngDiff = fSpreadAngle / TO_FLOAT(iCount - 1) fBaseAngle -= (fSpreadAngle / 2.0) REPEAT cnt ind fAngle = fBaseAngle + (TO_FLOAT(ind) * fAngDiff) GGSM_PROJECTILE_INIT(sGGSMData.sProjectiles[iProjList[ind]], eType, vPos, fAngle, FALSE) ENDREPEAT GGSM_PROJECTILE_DATA dat = GGSM_PROJECTILE_DATA_GET(eType) GGSM_PLAY_SOUND_FROM_POSITION(dat.eProjSound, vPos) ENDPROC /// PURPOSE: /// Gets the speed multiplied by timescale /// PARAMS: /// ent - /// RETURNS: /// FUNC FLOAT GGSM_GET_PROJECTILE_SPEED(GGSM_PROJECTILE &ent) GGSM_PROJECTILE_DATA dat = GGSM_PROJECTILE_DATA_GET(ent.eType) FLOAT spd = dat.fBaseSpeed IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_PROJECTILE_BIT_IS_PLAYER_ALLIED) spd *= sGGSMData.fTimeScale ENDIF RETURN spd ENDFUNC PROC GGSM_REFLECT_PROJECTILE(GGSM_PROJECTILE &ent) VECTOR_2D tmp IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_PROJECTILE_BIT_ACTIVE) EXIT ENDIF CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_PROJECTILE_BIT_FIRED_BY_PLAYER) IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_PROJECTILE_BIT_IS_PLAYER_ALLIED) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_PROJECTILE_BIT_IS_PLAYER_ALLIED) ELSE CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_PROJECTILE_BIT_IS_PLAYER_ALLIED) ENDIF // remove any homing capability CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_PROJECTILE_BIT_IS_HOMING) ent.iTargetIndex = GGSM_INVALID_ENTITY // make it face the other way tmp = ent.sCollider.sData.vCollisionVectors[0] ent.sCollider.sData.vCollisionVectors[0] = ent.sCollider.sData.vCollisionVectors[1] ent.sCollider.sData.vCollisionVectors[1] = tmp FLOAT ang = GET_HEADING_FROM_VECTOR_2D(ent.vDirection.x, ent.vDirection.y) IF GET_RANDOM_BOOL() ang += GET_RANDOM_FLOAT_IN_RANGE(-190.0, -181.0) ELSE ang += GET_RANDOM_FLOAT_IN_RANGE(-179.0, -160.0) ENDIF ent.vDirection = GGSM_GET_VECTOR_FROM_HEADING(ang) ent.fDistTravelled = 0.0 ENDPROC PROC GGSM_REFLECT_ENEMY_PROJECTILES() INT i REPEAT GGSM_MAX_PROJECTILES i IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sProjectiles[i].eFlags, GGSM_PROJECTILE_BIT_IS_PLAYER_ALLIED) GGSM_REFLECT_PROJECTILE(sGGSMData.sProjectiles[i]) ENDIF ENDREPEAT ENDPROC /// PURPOSE: /// Returns true if the bullet was destroyed and not turned into something else /// PARAMS: /// ent - /// RETURNS: /// FUNC BOOL GGSM_PROJECTILE_TAKE_DAMAGE(GGSM_PROJECTILE &ent) BOOL bIsAllied = IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_PROJECTILE_BIT_IS_PLAYER_ALLIED) GGSM_PROJECTILE_DATA dat IF (ent.eType = GGSM_PROJECTILE_EXP_SHELL) GGSM_PROJECTILE_INIT(ent, GGSM_PROJECTILE_BOMB_EXPLOSION, ent.sCollider.sAABB.vCenter, 0, bIsAllied) dat = GGSM_PROJECTILE_DATA_GET(GGSM_PROJECTILE_BOMB_EXPLOSION) GGSM_PLAY_SOUND_FROM_POSITION(dat.eProjSound, ent.sCollider.sAABB.vCenter) RETURN FALSE ENDIF IF (ent.eType = GGSM_PROJECTILE_BOMB_EXPLOSION) RETURN FALSE ENDIF IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_PROJECTILE_BIT_IS_CLUSTER_BOMB) AND NOT (bIsAllied) GGSM_PROJECTILE_CREATE_ENEMY_RADIAL_SPREAD(GGSM_PROJECTILE_ENEMY_SHOT, ent.sCollider.sAABB.vCenter, 5, 0, TRUE) ENDIF ent.eFlags = GGSM_PROJECTILE_BIT_NONE RETURN TRUE ENDFUNC /// PURPOSE: /// Update projectile and transform collision /// PARAMS: /// ent - projectile to update PROC GGSM_PROJECTILE_UPDATE_ACID(GGSM_PROJECTILE &ent) FLOAT spd = 0 +@ GGSM_GET_PROJECTILE_SPEED(ent) IF (ent.fDistTravelled > 300.0) ent.vDirection = LERP_VECTOR_2D(ent.vDirection, INIT_VECTOR_2D(-1, 0), 0.25) ENDIF ent.fDistTravelled += spd ent.sCollider.sData.vCollisionVectors[0].x += (ent.vDirection.x * spd) ent.sCollider.sData.vCollisionVectors[0].y += (ent.vDirection.y * spd) ent.sCollider.sData.vCollisionVectors[1] = ent.sCollider.sData.vCollisionVectors[0] IF (ent.sCollider.sData.eType = GGSM_COLLISION_CAPSULE) ent.sCollider.sData.vCollisionVectors[1].x += (ent.vDirection.x * ent.fLength) ent.sCollider.sData.vCollisionVectors[1].y += (ent.vDirection.y * ent.fLength) ENDIF ENDPROC /// PURPOSE: /// Update projectile and transform collision /// PARAMS: /// ent - projectile to update PROC GGSM_PROJECTILE_UPDATE_HOMING(GGSM_PROJECTILE &ent) FLOAT spd = 0 +@ GGSM_GET_PROJECTILE_SPEED(ent) VECTOR_2D dir, ndir IF (ent.iTargetIndex != GGSM_INVALID_ENTITY) IF (sGGSMData.sEntities[ent.iTargetIndex].eState = GGSM_ENTITY_STATE_ALIVE) dir = SUBTRACT_VECTOR_2D(sGGSMData.sEntities[ent.iTargetIndex].sCollider.sAABB.vCenter, ent.sCollider.sData.vCollisionVectors[0]) ndir = NORMALISE_VECTOR_2D(dir) ent.vDirection = LERP_VECTOR_2D(ent.vDirection, ndir, 0.25) ELSE ent.iTargetIndex = GGSM_INVALID_ENTITY ENDIF ENDIF ent.fDistTravelled += spd ent.sCollider.sData.vCollisionVectors[0].x += (ent.vDirection.x * spd) ent.sCollider.sData.vCollisionVectors[0].y += (ent.vDirection.y * spd) ent.sCollider.sData.vCollisionVectors[1] = ent.sCollider.sData.vCollisionVectors[0] IF (ent.sCollider.sData.eType = GGSM_COLLISION_CAPSULE) ent.sCollider.sData.vCollisionVectors[1].x += (ent.vDirection.x * ent.fLength) ent.sCollider.sData.vCollisionVectors[1].y += (ent.vDirection.y * ent.fLength) ENDIF ENDPROC /// PURPOSE: /// Update projectile and transform collision /// PARAMS: /// ent - projectile to update PROC GGSM_PROJECTILE_UPDATE_DELAYED_HOMING(GGSM_PROJECTILE &ent) FLOAT spd = 0 +@ GGSM_GET_PROJECTILE_SPEED(ent) VECTOR_2D dir, ndir INT ind IF (ent.fDistTravelled > 150.0) AND (ent.iTargetIndex = GGSM_INVALID_ENTITY) ent.iTargetIndex = GGSM_GET_CLOSEST_ENEMY_ENTITY_INDEX(sGGSMData.sEntities, ent.sCollider.sData.vCollisionVectors[0], IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_PROJECTILE_BIT_IS_PLAYER_ALLIED)) ENDIF IF (ent.iTargetIndex != GGSM_INVALID_ENTITY) IF (sGGSMData.sEntities[ent.iTargetIndex].eState = GGSM_ENTITY_STATE_ALIVE) dir = SUBTRACT_VECTOR_2D(sGGSMData.sEntities[ent.iTargetIndex].sCollider.sAABB.vCenter, ent.sCollider.sData.vCollisionVectors[0]) ndir = NORMALISE_VECTOR_2D(dir) ent.vDirection = LERP_VECTOR_2D(ent.vDirection, ndir, 0.125) ELSE ent.iTargetIndex = GGSM_INVALID_ENTITY ENDIF ENDIF ent.fDistTravelled += spd ent.sCollider.sData.vCollisionVectors[0].x += (ent.vDirection.x * spd) ent.sCollider.sData.vCollisionVectors[0].y += (ent.vDirection.y * spd) ent.sCollider.sData.vCollisionVectors[1] = ent.sCollider.sData.vCollisionVectors[0] IF (ent.sCollider.sData.eType = GGSM_COLLISION_CAPSULE) ent.sCollider.sData.vCollisionVectors[1].x += (ent.vDirection.x * ent.fLength) ent.sCollider.sData.vCollisionVectors[1].y += (ent.vDirection.y * ent.fLength) ENDIF IF (ent.fDistTravelled > 1200.0) IF GGSM_GET_FREE_FXSPRITE(sGGSMData.sFXSprite, ind, sGGSMData.iExplosionSearchIndex) GGSM_FXSPRITE_INIT_ANIMATED(sGGSMData.sFXSprite[ind], ent.sCollider.sAABB.vCenter, GGSM_SPRITE_ANIM_EXPLOSION, 2.0) GGSM_FXSPRITE_SET_PHYSICAL_RADIUS(sGGSMData.sFXSprite[ind], ent.fLength * 2.0) ENDIF ent.eFlags = GGSM_PROJECTILE_BIT_NONE ENDIF ENDPROC /// PURPOSE: /// Update projectile and transform collision /// PARAMS: /// ent - projectile to update PROC GGSM_PROJECTILE_UPDATE_SINWAVE(GGSM_PROJECTILE &ent) FLOAT fPeriod, fWaveHeight = 44.0 FLOAT spd = 0 +@ GGSM_GET_PROJECTILE_SPEED(ent) // move forward ent.fDistTravelled += spd ent.sCollider.sData.vCollisionVectors[0] = GGSM_UNPACK_VECTOR_2D(ent.iPackedOrigin) ent.sCollider.sData.vCollisionVectors[0].x += (ent.vDirection.x * ent.fDistTravelled) ent.sCollider.sData.vCollisionVectors[0].y += (ent.vDirection.y * ent.fDistTravelled) // horizontal displacement - get the perpendicular fPeriod = TO_FLOAT(FLOOR(ent.fDistTravelled) % FLOOR(600.0)) / 600.0 IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_PROJECTILE_BIT_IS_NEG_SINEWAVE) fWaveHeight *= -1.0 ENDIF spd = SIN(fPeriod * 360.0) * fWaveHeight ent.sCollider.sData.vCollisionVectors[0].x += (ent.vDirection.y * spd) ent.sCollider.sData.vCollisionVectors[0].y += (ent.vDirection.x * spd) ent.sCollider.sData.vCollisionVectors[1] = ent.sCollider.sData.vCollisionVectors[0] IF (ent.sCollider.sData.eType = GGSM_COLLISION_CAPSULE) ent.sCollider.sData.vCollisionVectors[1].x += (ent.vDirection.x * ent.fLength) ent.sCollider.sData.vCollisionVectors[1].y += (ent.vDirection.y * ent.fLength) ENDIF ENDPROC /// PURPOSE: /// Update projectile and transform collision /// PARAMS: /// ent - projectile to update PROC GGSM_PROJECTILE_UPDATE_STRAIGHT(GGSM_PROJECTILE &ent) FLOAT spd = 0 +@ GGSM_GET_PROJECTILE_SPEED(ent) ent.fDistTravelled += spd ent.sCollider.sData.vCollisionVectors[0].x += (ent.vDirection.x * spd) ent.sCollider.sData.vCollisionVectors[0].y += (ent.vDirection.y * spd) ent.sCollider.sData.vCollisionVectors[1] = ent.sCollider.sData.vCollisionVectors[0] IF (ent.sCollider.sData.eType = GGSM_COLLISION_CAPSULE) ent.sCollider.sData.vCollisionVectors[1].x += (ent.vDirection.x * ent.fLength) ent.sCollider.sData.vCollisionVectors[1].y += (ent.vDirection.y * ent.fLength) ENDIF ENDPROC /// PURPOSE: /// Update projectile and transform collision /// PARAMS: /// ent - projectile to update PROC GGSM_PROJECTILE_UPDATE_MARINE_BOMB(GGSM_PROJECTILE &ent) INT ind FLOAT spd = 0 +@ GGSM_GET_PROJECTILE_SPEED(ent) ent.fDistTravelled += spd ent.sCollider.sData.vCollisionVectors[0].x += (ent.vDirection.x * spd) ent.sCollider.sData.vCollisionVectors[0].y += (ent.vDirection.y * spd) ent.sCollider.sData.vCollisionVectors[1] = ent.sCollider.sData.vCollisionVectors[0] IF (ent.sCollider.sData.eType = GGSM_COLLISION_CAPSULE) ent.sCollider.sData.vCollisionVectors[1].x += (ent.vDirection.x * ent.fLength) ent.sCollider.sData.vCollisionVectors[1].y += (ent.vDirection.y * ent.fLength) ENDIF IF (ent.sCollider.sData.vCollisionVectors[0].x < 350.0) OR (ent.sCollider.sData.vCollisionVectors[0].x > 1580.0) OR (ent.sCollider.sData.vCollisionVectors[0].y < 110.0) OR (ent.sCollider.sData.vCollisionVectors[0].y > 990.0) GGSM_PROJECTILE_CREATE_ENEMY_CONE_SPREAD(GGSM_PROJECTILE_ENEMY_SHOT, ent.sCollider.sAABB.vCenter, 90.0, GET_RANDOM_INT_IN_RANGE(3, 5), TRUE) IF GGSM_GET_FREE_FXSPRITE(sGGSMData.sFXSprite, ind, sGGSMData.iExplosionSearchIndex) GGSM_FXSPRITE_INIT_ANIMATED(sGGSMData.sFXSprite[ind], ent.sCollider.sAABB.vCenter, GGSM_SPRITE_ANIM_EXPLOSION, 2.0) GGSM_FXSPRITE_SET_PHYSICAL_RADIUS(sGGSMData.sFXSprite[ind], ent.fLength * 2.0) ENDIF ent.eFlags = GGSM_PROJECTILE_BIT_NONE ENDIF ENDPROC PROC GGSM_PROJECTILE_UPDATE_BOMB_EXPLOSION(GGSM_PROJECTILE &ent) UNUSED_PARAMETER(ent) ENDPROC /// PURPOSE: /// Update projectile and transform collision /// PARAMS: /// ent - projectile to update PROC GGSM_PROJECTILE_UPDATE(GGSM_PROJECTILE &ent) // update timer IF (IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_PROJECTILE_BIT_IS_PLAYER_ALLIED)) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_PLAYER_PROJECTILES_ACTIVE) ent.fTimer += sGGSMData.fDeltaTime ELSE SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_ENEMY_PROJECTILES_ACTIVE) ent.fTimer += (sGGSMData.fDeltaTime * sGGSMData.fTimeScale) IF GGSM_IS_PLAYER_SHIP_ALIVE() IF (GET_GAME_TIMER() > sGGSMData.sEntities[sGGSMData.iPlayerShipIndex].iInvTimeMS) IF VECTOR_2D_DIST2(ent.sCollider.sAABB.vCenter, sGGSMData.sEntities[sGGSMData.iPlayerShipIndex].sWorld.vPosition) < (sGGSMData.fGrazeRadius * sGGSMData.fGrazeRadius) sGGSMData.bGrazed = TRUE ENDIF ENDIF ENDIF sGGSMData.iEnemyProjectilesActive ++ ENDIF IF (ent.eType = GGSM_PROJECTILE_ACID) GGSM_PROJECTILE_UPDATE_ACID(ent) ELIF (ent.eType = GGSM_PROJECTILE_BOMB_EXPLOSION) GGSM_PROJECTILE_UPDATE_BOMB_EXPLOSION(ent) ELIF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_PROJECTILE_BIT_IS_SINEWAVE) GGSM_PROJECTILE_UPDATE_SINWAVE(ent) ELIF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_PROJECTILE_BIT_IS_HOMING) GGSM_PROJECTILE_UPDATE_HOMING(ent) ELIF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_PROJECTILE_BIT_IS_DELAYED_HOMING) GGSM_PROJECTILE_UPDATE_DELAYED_HOMING(ent) ELIF (ent.eType = GGSM_PROJECTILE_MARINE_LAUNCHER) GGSM_PROJECTILE_UPDATE_MARINE_BOMB(ent) ELSE GGSM_PROJECTILE_UPDATE_STRAIGHT(ent) ENDIF IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_PROJECTILE_BIT_IS_CLUSTER_BOMB) IF (VECTOR_2D_DIST2(ent.sCollider.sData.vCollisionVectors[0], GGSM_GET_TARGET_AT_PLAYER_POSITION()) < (400.0 * 400.0)) OR (ent.fDistTravelled > 700.0) GGSM_PROJECTILE_TAKE_DAMAGE(ent) ENDIF ENDIF sGGSMData.iProjectilesActive ++ GGSM_COLLIDER_CALCULATE_AABB(ent.sCollider) IF NOT GGSM_IS_COLLIDER_AABB_ON_SCREEN(ent.sCollider) ent.eFlags = GGSM_PROJECTILE_BIT_NONE EXIT ENDIF ENDPROC /// PURPOSE: /// Update the projectile array /// PARAMS: /// array - array /// RETURNS: /// # of active projectiles FUNC BOOL GGSM_UPDATE_PROJECTILE_ARRAY(GGSM_PROJECTILE &array[]) INT i INT cnt = COUNT_OF(array) BOOL bActiveCheck = FALSE sGGSMData.iProjectilesActive = 0 sGGSMData.iEnemyProjectilesActive = 0 REPEAT cnt i IF IS_BITMASK_ENUM_AS_ENUM_SET(array[i].eFlags, GGSM_PROJECTILE_BIT_ACTIVE) GGSM_PROJECTILE_UPDATE(array[i]) bActiveCheck = TRUE ENDIF ENDREPEAT IF (sGGSMData.iProjectilesActive > sGGSMData.iMaxProjectilesActive) sGGSMData.iMaxProjectilesActive = sGGSMData.iProjectilesActive ENDIF RETURN bActiveCheck ENDFUNC /// PURPOSE: /// Update the projectile array /// PARAMS: /// array - array /// RETURNS: /// # of active projectiles PROC GGSM_DESTROY_ALL_FACTION_BULLETS(GGSM_PROJECTILE &array[], BOOL bAllied) INT i INT cnt = COUNT_OF(array) REPEAT cnt i IF IS_BITMASK_ENUM_AS_ENUM_SET(array[i].eFlags, GGSM_PROJECTILE_BIT_ACTIVE) IF (IS_BITMASK_ENUM_AS_ENUM_SET(array[i].eFlags, GGSM_PROJECTILE_BIT_IS_PLAYER_ALLIED) = bAllied) array[i].eFlags = GGSM_PROJECTILE_BIT_NONE ENDIF ENDIF ENDREPEAT ENDPROC //------------------------------------------------- // ENTITY QUERY FUNCTIONS //------------------------------------------------- FUNC BOOL GGSM_ENTITY_IS_MAIN_BOSS_SECTION(GGSM_ENTITY &ent) IF (ent.eType = GGSM_ENTITY_BOSS_BREAD_FACE) RETURN TRUE ENDIF IF (ent.eType = GGSM_ENTITY_BOSS_GRANANA) RETURN TRUE ENDIF IF (ent.eType = GGSM_ENTITY_BOSS_MARINE) RETURN TRUE ENDIF IF (ent.eType = GGSM_ENTITY_BOSS_SMOOTHIE) RETURN TRUE ENDIF IF (ent.eType = GGSM_ENTITY_BOSS_DR_DANK_TOP) RETURN TRUE ENDIF RETURN FALSE ENDFUNC FUNC BOOL GGSM_ENTITY_IS_STRONG(GGSM_ENTITY &ent) IF GGSM_ENTITY_IS_MAIN_BOSS_SECTION(ent) RETURN TRUE ENDIF SWITCH (ent.eType) CASE GGSM_ENTITY_ARMOUR_FRUITBOWL CASE GGSM_ENTITY_BANANASLICE_FRONT CASE GGSM_ENTITY_BANANASLICE CASE GGSM_ENTITY_BANANASLICE_BACK CASE GGSM_ENTITY_BOSS_BREAD_FACE CASE GGSM_ENTITY_BOSS_BREAD_BOTTOM_LEFT CASE GGSM_ENTITY_BOSS_BREAD_BOTTOM_RIGHT CASE GGSM_ENTITY_BOSS_BREAD_TOP_LEFT CASE GGSM_ENTITY_BOSS_BREAD_TOP_RIGHT CASE GGSM_ENTITY_BANANASPLIT_1 CASE GGSM_ENTITY_BANANASPLIT_2 CASE GGSM_ENTITY_BANANASPLIT_3 CASE GGSM_ENTITY_BANANASPLIT_4 CASE GGSM_ENTITY_BOSS_MARINE CASE GGSM_ENTITY_BOSS_GRANANA CASE GGSM_ENTITY_BOSS_GRANANA_HAIR CASE GGSM_ENTITY_BOSS_DR_DANK_TOP CASE GGSM_ENTITY_BOSS_DR_DANK_MIDDLE CASE GGSM_ENTITY_BOSS_DR_DANK_BOTTOM CASE GGSM_ENTITY_BOSS_SMOOTHIE RETURN TRUE ENDSWITCH RETURN FALSE ENDFUNC FUNC INT GGSM_ENTITY_GET_PERCENTAGE_OF_HEALTH(GGSM_ENTITY &ent, FLOAT fPc) GGSM_ENTITY_DATA dat = GGSM_ENTITY_DATA_GET(ent.eType) RETURN CEIL(TO_FLOAT(dat.iMaxHP) * (fpc / 100.0)) ENDFUNC FUNC BOOL GGSM_ENTITY_HAS_COLLISION(GGSM_ENTITY &ent) IF (ent.eState != GGSM_ENTITY_STATE_ALIVE) RETURN FALSE ENDIF RETURN NOT IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_NO_COLLISION) ENDFUNC FUNC BOOL GGSM_ENTITY_CAN_COLLIDE_WITH(GGSM_ENTITY &ent, GGSM_ENTITY &ent2) IF (IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_IS_PLAYER_ALLIED) = IS_BITMASK_ENUM_AS_ENUM_SET(ent2.eFlags, GGSM_ENTITY_BIT_IS_PLAYER_ALLIED)) RETURN FALSE ENDIF IF NOT GGSM_ENTITY_HAS_COLLISION(ent) RETURN FALSE ENDIF RETURN GGSM_ENTITY_HAS_COLLISION(ent2) ENDFUNC FUNC BOOL GGSM_ENTITY_CAN_COLLIDE_WITH_PROJECTILE(GGSM_ENTITY &ent, GGSM_PROJECTILE &proj) IF (IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_IS_PLAYER_ALLIED) = IS_BITMASK_ENUM_AS_ENUM_SET(proj.eFlags, GGSM_PROJECTILE_BIT_IS_PLAYER_ALLIED)) RETURN FALSE ENDIF IF NOT GGSM_ENTITY_HAS_COLLISION(ent) RETURN FALSE ENDIF RETURN GGSM_PROJECTILE_HAS_COLLISION(proj) ENDFUNC FUNC FLOAT GGSM_ENTITY_GET_HP_PERCENTAGE(GGSM_ENTITY &ent) IF (ent.eState != GGSM_ENTITY_STATE_ALIVE) RETURN 0.0 ENDIF GGSM_ENTITY_DATA dat = GGSM_ENTITY_DATA_GET(ent.eType) RETURN TO_FLOAT(ent.iHP) / TO_FLOAT(dat.iMaxHP) ENDFUNC PROC GGSM_ENTITY_SET_ANIM_FRAME(GGSM_ENTITY &ent, INT iAnimFrame = -1, BOOL bStopAnim = FALSE) IF (iAnimFrame = -1) GGSM_ENTITY_DATA dat = GGSM_ENTITY_DATA_GET(ent.eType) ent.fAnimFrame = TO_FLOAT(dat.iDefaultAnimFrame) ELSE ent.fAnimFrame = TO_FLOAT(iAnimFrame) ENDIF IF (bStopAnim) ent.eSpriteAnim = GGSM_SPRITE_ANIM_NONE ENDIF ENDPROC FUNC BOOL GGSM_ENTITY_SET_ANIMATION(GGSM_ENTITY &ent, GGSM_SPRITE_ANIM eType) GGSM_SPRITE_ANIM_DATA data IF (eType = GGSM_SPRITE_ANIM_NONE) ent.eSpriteAnim = eType RETURN FALSE ENDIF IF NOT GGSM_GET_SPRITE_ANIM_DATA(eType, data) RETURN FALSE ENDIF ent.eSpriteAnim = eType ent.fAnimFrame = data.fStartFrame RETURN TRUE ENDFUNC PROC GGSM_ENTITY_DETACH_FROM_PARENT(GGSM_ENTITY &ent) GGSM_ENTITY_SET_PARENT_INDEX(ent, GGSM_INVALID_ENTITY) ent.sLocal = ent.sWorld ENDPROC //------------------------------------------------- // ENTITY WEAPON FUNCTIONS //------------------------------------------------- PROC GGSM_ENTITY_SET_WEAPON_STATE(GGSM_ENTITY &ent, GGSM_WEAPON_STATE eState, BOOL bResetTimer = TRUE) ent.eWeaponState = eState IF (bResetTimer) ent.fWeaponTimer = 0 ENDIF ENDPROC PROC GGSM_ENTITY_SET_WEAPON(GGSM_ENTITY &ent, GGSM_WEAPON_TYPE eType) GGSM_ENTITY_DATA entData = GGSM_ENTITY_DATA_GET(ent.eType) IF (eType = GGSM_WEAPON_DEFAULT) eType = entData.eWeaponType ENDIF ent.eWeaponType = eType ent.iWeaponShotCounter = 0 ent.iWeaponBurstCounter = 0 IF (ent.eWeaponType = GGSM_WEAPON_NONE) EXIT ENDIF ENDPROC FUNC VECTOR_2D GGSM_ENTITY_GET_GUN_WORLD_POS(GGSM_ENTITY &ent) GGSM_ENTITY_DATA entData = GGSM_ENTITY_DATA_GET(ent.eType) RETURN GGSM_TRANSFORM_LOCAL_POS_TO_WORLD_POS(ent.sWorld, entData.sGunPos.vPosition) ENDFUNC FUNC BOOL GGSM_ENTITY_FIRE_WEAPON(GGSM_ENTITY &ent) IF (ent.eWeaponType = GGSM_WEAPON_NONE) OR (ent.eWeaponType = GGSM_WEAPON_INVALID) RETURN FALSE ENDIF IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.eStageFlags, GGSM_STAGE_BIT_DISABLE_WEAPONS) RETURN FALSE ENDIF INT ind, cnt FLOAT fBaseAngle VECTOR_2D tgtPos, dir, shotPos BOOL bIsAllied = IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_IS_PLAYER_ALLIED) BOOL bIsRandomSpread = IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_WPN_RANDOM_SPREAD) // handle targeting GGSM_ENTITY_DATA entData = GGSM_ENTITY_DATA_GET(ent.eType) VECTOR_2D gunPos = GGSM_TRANSFORM_LOCAL_POS_TO_WORLD_POS(ent.sWorld, entData.sGunPos.vPosition) fBaseAngle = ent.sWorld.fRotation + entData.sGunPos.fRotation IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) AND NOT bIsAllied tgtPos = GGSM_GET_TARGET_AT_PLAYER_POSITION() dir = SUBTRACT_VECTOR_2D(tgtPos, gunPos) fBaseAngle = GET_HEADING_FROM_VECTOR_2D(dir.x, dir.y) ENDIF // get data from weapon GGSM_WEAPON_DATA wpnData = GGSM_WEAPON_DATA_GET(ent.eWeaponType) INT iNumShots = wpnData.iNumShots BOOL bBurstDone IF (ent.iNumShotsOverride > 0) iNumShots = ent.iNumShotsOverride ENDIF IF (sGGSMData.bHardMode) AND (NOT bIsAllied) AND (iNumShots > 1) iNumShots ++ ENDIF FLOAT wSpread INT iProjList[16] FLOAT fAngle, fAngDiff = 360.0 / TO_FLOAT(iNumShots) SWITCH (wpnData.eSpreadType) CASE GGSM_SPREAD_LINEAR IF GGSM_GET_FREE_PROJECTILE(sGGSMData.sProjectiles, ind, sGGSMData.iProjectileSearchIndex) GGSM_PROJECTILE_INIT(sGGSMData.sProjectiles[ind], wpnData.eProjectileType, gunPos, fBaseAngle, bIsAllied) ent.iWeaponShotCounter ++ bBurstDone = TRUE ENDIF BREAK CASE GGSM_SPREAD_RADIAL IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_WPN_ALT_SPREAD) IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_WPN_FIRED_ALT_SPREAD) fBaseAngle += (fAngDiff / 2.0) ENDIF ENDIF IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_WPN_SINGLE_SHOT_MODE) cnt = GGSM_GET_FREE_PROJECTILES(sGGSMData.sProjectiles, 1, iProjList, sGGSMData.iProjectileSearchIndex) fAngle = fBaseAngle + (TO_FLOAT(ent.iWeaponShotCounter) * fAngDiff) IF (bIsRandomSpread) fAngle = GET_RANDOM_FLOAT_IN_RANGE(0.0, 360.0) ENDIF GGSM_PROJECTILE_INIT(sGGSMData.sProjectiles[iProjList[0]], wpnData.eProjectileType, gunPos, fAngle, bIsAllied) ent.iWeaponShotCounter ++ IF (ent.iWeaponShotCounter >= iNumShots) bBurstDone = TRUE ent.iWeaponShotCounter = 0 ENDIF ELSE cnt = GGSM_GET_FREE_PROJECTILES(sGGSMData.sProjectiles, iNumShots, iProjList, sGGSMData.iProjectileSearchIndex) REPEAT cnt ind fAngle = fBaseAngle + (TO_FLOAT(ind) * fAngDiff) IF (bIsRandomSpread) fAngle = GET_RANDOM_FLOAT_IN_RANGE(0.0, 360.0) ENDIF GGSM_PROJECTILE_INIT(sGGSMData.sProjectiles[iProjList[ind]], wpnData.eProjectileType, gunPos, fAngle, bIsAllied) ENDREPEAT ent.iWeaponShotCounter = 0 bBurstDone = TRUE ENDIF BREAK CASE GGSM_SPREAD_CONE IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_WPN_ALT_SPREAD) IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_WPN_FIRED_ALT_SPREAD) iNumShots ++ ENDIF ENDIF fAngDiff = wpnData.fSpreadValue / TO_FLOAT(iNumShots - 1) fBaseAngle -= (wpnData.fSpreadValue / 2.0) IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_WPN_SINGLE_SHOT_MODE) cnt = GGSM_GET_FREE_PROJECTILES(sGGSMData.sProjectiles, 1, iProjList, sGGSMData.iProjectileSearchIndex) fAngle = fBaseAngle + (TO_FLOAT(ent.iWeaponShotCounter) * fAngDiff) IF (bIsRandomSpread) fAngle = fBaseAngle + (GET_RANDOM_FLOAT_IN_RANGE(0.0, TO_FLOAT(iNumShots)) * fAngDiff) ENDIF GGSM_PROJECTILE_INIT(sGGSMData.sProjectiles[iProjList[0]], wpnData.eProjectileType, gunPos, fAngle, bIsAllied) ent.iWeaponShotCounter ++ IF (ent.iWeaponShotCounter >= iNumShots) bBurstDone = TRUE ent.iWeaponShotCounter = 0 ENDIF ELSE cnt = GGSM_GET_FREE_PROJECTILES(sGGSMData.sProjectiles, iNumShots, iProjList, sGGSMData.iProjectileSearchIndex) REPEAT cnt ind fAngle = fBaseAngle + (TO_FLOAT(ind) * fAngDiff) IF (bIsRandomSpread) fAngle = fBaseAngle + (GET_RANDOM_FLOAT_IN_RANGE(0.0, TO_FLOAT(iNumShots)) * fAngDiff) ENDIF GGSM_PROJECTILE_INIT(sGGSMData.sProjectiles[iProjList[ind]], wpnData.eProjectileType, gunPos, fAngle, bIsAllied) ent.iWeaponShotCounter = 0 bBurstDone = TRUE ENDREPEAT ENDIF BREAK CASE GGSM_SPREAD_WAVE IF GGSM_GET_FREE_PROJECTILE(sGGSMData.sProjectiles, ind, sGGSMData.iProjectileSearchIndex) wSpread = (wpnData.fSpreadValue / 2.0) dir = GGSM_GET_VECTOR_FROM_HEADING(fBaseAngle) shotPos = gunpos IF (ent.iWeaponShotCounter % 3 = 2) shotPos.x -= dir.y * wSpread shotPos.y -= dir.x * wSpread ELIF (ent.iWeaponShotCounter % 3 = 0) shotPos.x += dir.y * wSpread shotPos.y += dir.x * wSpread ENDIF GGSM_PROJECTILE_INIT(sGGSMData.sProjectiles[ind], wpnData.eProjectileType, shotPos, fBaseAngle, bIsAllied) ent.iWeaponShotCounter ++ bBurstDone = TRUE ENDIF BREAK CASE GGSM_SPREAD_DUALARCH cnt = GGSM_GET_FREE_PROJECTILES(sGGSMData.sProjectiles, 2, iProjList, sGGSMData.iProjectileSearchIndex) IF (cnt = 2) GGSM_PROJECTILE_INIT(sGGSMData.sProjectiles[iProjList[0]], wpnData.eProjectileType, gunpos, fBaseAngle, bIsAllied) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sProjectiles[iProjList[0]].eFlags, GGSM_PROJECTILE_BIT_IS_SINEWAVE) GGSM_PROJECTILE_INIT(sGGSMData.sProjectiles[iProjList[1]], wpnData.eProjectileType, gunpos, fBaseAngle, bIsAllied) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sProjectiles[iProjList[1]].eFlags, GGSM_PROJECTILE_BIT_IS_SINEWAVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sProjectiles[iProjList[1]].eFlags, GGSM_PROJECTILE_BIT_IS_NEG_SINEWAVE) bBurstDone = TRUE ENDIF BREAK CASE GGSM_SPREAD_BACKVULCAN cnt = GGSM_GET_FREE_PROJECTILES(sGGSMData.sProjectiles, 3, iProjList, sGGSMData.iProjectileSearchIndex) wSpread = (wpnData.fSpreadValue / 2.0) dir = GGSM_GET_VECTOR_FROM_HEADING(fBaseAngle) IF (cnt = 3) shotPos = gunpos shotPos.x -= dir.y * wSpread shotPos.y -= dir.x * wSpread GGSM_PROJECTILE_INIT(sGGSMData.sProjectiles[iProjList[0]], wpnData.eProjectileType, shotPos, fBaseAngle - 180.0, bIsAllied) shotPos = gunpos shotPos.x += dir.y * wSpread shotPos.y += dir.x * wSpread GGSM_PROJECTILE_INIT(sGGSMData.sProjectiles[iProjList[1]], wpnData.eProjectileType, shotPos, fBaseAngle - 180.0, bIsAllied) GGSM_PROJECTILE_INIT(sGGSMData.sProjectiles[iProjList[2]], wpnData.eProjectileType, gunpos, fBaseAngle, bIsAllied) bBurstDone = TRUE ENDIF BREAK ENDSWITCH IF (bBurstDone = TRUE) IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_WPN_FIRED_ALT_SPREAD) CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_FIRED_ALT_SPREAD) ELSE SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_FIRED_ALT_SPREAD) ENDIF SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_BURST_FIRED) ent.iWeaponBurstCounter ++ ENDIF SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_FIRED_THIS_FRAME) GGSM_ENTITY_SET_WEAPON_STATE(ent, GGSM_WEAPON_STATE_FIRED) GGSM_PROJECTILE_DATA projData = GGSM_PROJECTILE_DATA_GET(wpnData.eProjectileType) GGSM_PLAY_SOUND_FROM_POSITION(projData.eProjSound, gunpos) RETURN TRUE ENDFUNC PROC GGSM_ENTITY_UPDATE_WEAPON(GGSM_ENTITY &ent) CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_FIRED_THIS_FRAME) CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_BURST_FIRED) CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_BURST_RELOAD_THIS_FRAME) IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_ENTERED_PLAYFIELD) EXIT ENDIF IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_ON_SCREEN) EXIT ENDIF IF GGSM_IS_DIALOG_ACTIVE() EXIT ENDIF // handle slow down GGSM_PROJECTILE_DATA projdata GGSM_WEAPON_DATA wpnData = GGSM_WEAPON_DATA_GET(ent.eWeaponType) FLOAT fDelta = GET_FRAME_TIME() BOOL bIsAllied = IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_IS_PLAYER_ALLIED) IF (bIsAllied) ent.fWeaponTimer += fDelta ELSE ent.fWeaponTimer += (fDelta * sGGSMData.fTimeScale) ENDIF // update state SWITCH (ent.eWeaponState) CASE GGSM_WEAPON_STATE_READY projdata = GGSM_PROJECTILE_DATA_GET(wpnData.eProjectileType) IF (ent.fWeaponTimer >= projdata.fShotReloadTime) GGSM_ENTITY_SET_WEAPON_STATE(ent, GGSM_WEAPON_STATE_FIRING) ENDIF BREAK CASE GGSM_WEAPON_STATE_FIRING IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) GGSM_ENTITY_FIRE_WEAPON(ent) ENDIF BREAK CASE GGSM_WEAPON_STATE_FIRED IF (wpnData.iNumBursts <= 0) OR (ent.iWeaponBurstCounter < wpnData.iNumBursts) GGSM_ENTITY_SET_WEAPON_STATE(ent, GGSM_WEAPON_STATE_RELOAD) ELSE GGSM_ENTITY_SET_WEAPON_STATE(ent, GGSM_WEAPON_STATE_BURST_RELOAD) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_BURST_RELOAD_THIS_FRAME) ENDIF BREAK CASE GGSM_WEAPON_STATE_RELOAD projdata = GGSM_PROJECTILE_DATA_GET(wpnData.eProjectileType) IF (ent.fWeaponTimer >= projdata.fShotReloadTime) GGSM_ENTITY_SET_WEAPON_STATE(ent, GGSM_WEAPON_STATE_FIRING) ENDIF BREAK CASE GGSM_WEAPON_STATE_BURST_RELOAD IF (ent.fWeaponTimer >= wpnData.fBurstReloadTime) ent.iWeaponBurstCounter = 0 GGSM_ENTITY_SET_WEAPON_STATE(ent, GGSM_WEAPON_STATE_SPINUP) ENDIF BREAK CASE GGSM_WEAPON_STATE_SPINUP GGSM_ENTITY_SET_WEAPON_STATE(ent, GGSM_WEAPON_STATE_FIRING) BREAK ENDSWITCH ENDPROC //------------------------------------------------- // ENTITY MOVEMENT FUNCTIONS //------------------------------------------------- PROC GGSM_ENTITY_SET_MOVEMENT_STATE(GGSM_ENTITY &ent, GGSM_MOVESTATE_TYPE st) ent.eMoveState = st ent.fMoveTimer = 0.0 CDEBUG1LN(DEBUG_MINIGAME, "GGSM_ENTITY_SET_MOVEMENT_STATE - TYPE:", GGSM_ENTITY_TYPE_TO_STRING(ent.eType), " ARRAY INDEX:", GGSM_ENTITY_GET_ARRAY_INDEX(ent), " MOVETYPE:", GGSM_MOVEMENT_TYPE_TO_STRING(ent.eMoveType), " STATE:", GGSM_MOVESTATE_TYPE_TO_STRING(st)) ENDPROC PROC GGSM_ENTITY_SET_TARGET_LOCAL_VECTOR(GGSM_ENTITY &ent, VECTOR_2D localTgtPos) ent.iPackedLocalTargetPosition = GGSM_PACK_VECTOR_2D_TO_INT(localTgtPos) ent.vLocalDirection = SUBTRACT_VECTOR_2D(localTgtPos, ent.sLocal.vPosition) ent.vLocalDirection = NORMALISE_VECTOR_2D(ent.vLocalDirection) CLEAR_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_TARGET_POINT_REACHED) CLEAR_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_TARGET_POINT_REACHED_THIS_FRAME) IF GGSM_IS_POINT_BEHIND_PLANE(localTgtPos, ent.vLocalDirection, ent.sLocal.vPosition) SET_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_LAST_PLANE_SIDE) ELSE CLEAR_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_LAST_PLANE_SIDE) ENDIF ENDPROC PROC GGSM_ENTITY_SET_TARGET_WORLD_VECTOR(GGSM_ENTITY &ent, VECTOR_2D vWorldPos) VECTOR_2D localTgtPos = vWorldPos INT iParentIndex = GGSM_ENTITY_GET_PARENT_INDEX(ent) // convert world position into target space IF (iParentIndex != GGSM_INVALID_ENTITY) localTgtPos = GGSM_TRANSFORM_WORLD_POS_TO_LOCAL_POS(sGGSMData.sEntities[iParentIndex].sWorld, vWorldPos) ENDIF GGSM_ENTITY_SET_TARGET_LOCAL_VECTOR(ent, localTgtPos) ENDPROC /// PURPOSE: /// Sets the movement type /// PARAMS: /// ent - entity to set /// eType - movement /// fMParam1 - param 1 /// fMparam2 - param 2 /// NOTE: For different movetypes the params are different /// GGSM_MOVEMENT_BG_ATTACK - mParam1 = how to move before scaling in (default is 800.0) /// GGSM_MOVEMENT_FORWARD_THEN_BACK - mParam1 = how far to move forward /// GGSM_MOVEMENT_ORBIT - mParam1 = dist from center, mParam2 = start angle, mParam3 = revs / sec /// GGSM_MOVEMENT_SINWAVE - mParam1 = period length (dist of 1 wave), mParam2 = height of wave /// GGSM_MOVEMENT_TARGETTED_WANDER - mParam1 = how long to wait at target, PROC GGSM_ENTITY_SET_MOVEMENT_TYPE(GGSM_ENTITY &ent, GGSM_MOVEMENT_TYPE eType, FLOAT fMParam1 = 0.0, FLOAT fMparam2 = 0.0, FLOAT fMparam3 = 0.0) ent.eMoveType = eType ent.eMoveState = GGSM_MOVESTATE_START ent.fMoveParam[0] = fMParam1 ent.fMoveParam[1] = fMParam2 ent.fMoveParam[2] = fMParam3 ent.eMoveFlags = GGSM_MOVE_BIT_NONE ent.fMoveTimer = 0.0 // do setups based on type SWITCH (eType) CASE GGSM_MOVEMENT_BG_ATTACK IF (ent.fMoveParam[0] = 0.0) ent.fMoveParam[0] = 950.0 ENDIF BREAK CASE GGSM_MOVEMENT_FORWARD_THEN_BACK IF (ent.fMoveParam[0] = 0.0) ent.fMoveParam[0] = 700.0 ENDIF BREAK CASE GGSM_MOVEMENT_SIN_WAVE ent.iPackedLocalOrigin = GGSM_PACK_VECTOR_2D_TO_INT(ent.sLocal.vPosition) BREAK CASE GGSM_MOVEMENT_SNAKE_SECTION SET_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_POSITION_OVERRIDE) BREAK ENDSWITCH ENDPROC PROC GGSM_ENTITY_SET_MOVEMENT_ORBIT(GGSM_ENTITY &ent, FLOAT fRange, FLOAT fStartAngle = 0.0, FLOAT fRevsPerSec = 1.0) GGSM_ENTITY_SET_MOVEMENT_TYPE(ent, GGSM_MOVEMENT_ORBIT, fRange, fStartAngle, fRevsPerSec) ENDPROC PROC GGSM_ENTITY_RETURN_TO_ORIGIN(GGSM_ENTITY &ent) VECTOR_2D tmp = GGSM_UNPACK_VECTOR_2D(ent.iPackedLocalOrigin) GGSM_ENTITY_SET_MOVEMENT_TYPE(ent, GGSM_MOVEMENT_MOVE_TO_VECTOR) GGSM_ENTITY_SET_TARGET_LOCAL_VECTOR(ent, tmp) ENDPROC PROC GGSM_ENTITY_SET_MOVEMENT_TO_LOCAL_VECTOR(GGSM_ENTITY &ent, VECTOR_2D vec, FLOAT fDelay = 0.0) GGSM_ENTITY_SET_MOVEMENT_TYPE(ent, GGSM_MOVEMENT_MOVE_TO_VECTOR, fDelay) GGSM_ENTITY_SET_TARGET_LOCAL_VECTOR(ent, vec) ENDPROC PROC GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(GGSM_ENTITY &ent, VECTOR_2D vec, FLOAT fDelay = 0.0) GGSM_ENTITY_SET_MOVEMENT_TYPE(ent, GGSM_MOVEMENT_MOVE_TO_VECTOR, fDelay) GGSM_ENTITY_SET_TARGET_WORLD_VECTOR(ent, vec) ENDPROC PROC GGSM_ENTITY_SET_MOVEMENT_TO_FACE_LOCAL_VECTOR(GGSM_ENTITY &ent, VECTOR_2D vec, FLOAT fDelay = 0.0) GGSM_ENTITY_SET_MOVEMENT_TYPE(ent, GGSM_MOVEMENT_ROTATE_TO_FACE_VECTOR, fDelay) GGSM_ENTITY_SET_TARGET_LOCAL_VECTOR(ent, vec) ENDPROC PROC GGSM_ENTITY_SET_MOVEMENT_TO_FACE_VECTOR(GGSM_ENTITY &ent, VECTOR_2D vec, FLOAT fDelay = 0.0) GGSM_ENTITY_SET_MOVEMENT_TYPE(ent, GGSM_MOVEMENT_ROTATE_TO_FACE_VECTOR, fDelay) GGSM_ENTITY_SET_TARGET_WORLD_VECTOR(ent, vec) ENDPROC PROC GGSM_ENTITY_SET_LOCAL_TRANSFORM(GGSM_ENTITY &ent, FLOAT x, FLOAT y, FLOAT rot) ent.sLocal.vPosition.x = x ent.sLocal.vPosition.y = y ent.sLocal.fRotation = rot ENDPROC FUNC BOOL GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(GGSM_ENTITY &ent, FLOAT spd, BOOL bMultByFrameTime = FALSE) BOOL bCurCheck VECTOR_2D dir VECTOR_2D localTgtPos = GGSM_UNPACK_VECTOR_2D(ent.iPackedLocalTargetPosition) FLOAT fAngle IF (bMultByFrameTime) spd = 0 +@ spd ENDIF ent.fDistTravelled += spd ent.sLocal.vPosition.x += (ent.vLocalDirection.x * spd) ent.sLocal.vPosition.y += (ent.vLocalDirection.y * spd) IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eMoveFlags, GGSM_MOVE_BIT_ROTATE_TO_FACE_DIRECTION) dir = SUBTRACT_VECTOR_2D(localTgtPos, ent.sLocal.vPosition) fAngle = GET_HEADING_FROM_VECTOR_2D(dir.x, dir.y) - ent.sLocal.fRotation IF (fAngle > 180.0) fAngle -= 360.0 ENDIF IF (fAngle < -180.0) fAngle += 360.0 ENDIF ent.sLocal.fRotation += (0 +@ fAngle) ENDIF // we've crossed the plane bCurCheck = GGSM_IS_POINT_BEHIND_PLANE(localTgtPos, ent.vLocalDirection, ent.sLocal.vPosition) IF (bCurCheck != IS_BITMASK_ENUM_AS_ENUM_SET(ent.eMoveFlags, GGSM_MOVE_BIT_LAST_PLANE_SIDE)) OR (VECTOR_2D_DIST2(localTgtPos, ent.sLocal.vPosition) <= 1) SET_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_TARGET_POINT_REACHED) SET_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_TARGET_POINT_REACHED_THIS_FRAME) ent.sLocal.vPosition = localTgtPos IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_WPN_FIRE_ON_ARRIVE) GGSM_ENTITY_FIRE_WEAPON(ent) ENDIF RETURN TRUE ENDIF IF (bCurCheck) SET_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_LAST_PLANE_SIDE) ELSE CLEAR_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_LAST_PLANE_SIDE) ENDIF RETURN FALSE ENDFUNC FUNC BOOL GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET_SCALER(GGSM_ENTITY &ent, FLOAT spd, FLOAT fScaleDist = 400.0, BOOL bMultByFrameTime = FALSE, BOOL bScaleOut = FALSE) IF GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, spd, bMultByFrameTime) ent.sLocal.vScale = INIT_VECTOR_2D(1.0, 1.0) CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_NO_COLLISION) RETURN TRUE ENDIF VECTOR_2D localTgtPos = GGSM_UNPACK_VECTOR_2D(ent.iPackedLocalTargetPosition) FLOAT fDist = VECTOR_2D_DIST(localTgtPos, ent.sLocal.vPosition) FLOAT fScale = ((fScaleDist - fDist) / fScaleDist) fScale = CLAMP(fScale, 0.25, 1.0) ent.sLocal.vScale = INIT_VECTOR_2D(fScale, fScale) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_NO_COLLISION) CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) UNUSED_PARAMETER(bScaleOut) RETURN FALSE ENDFUNC PROC GGSM_ENTITY_PRE_CALCULATE_FOR_ARC(GGSM_ENTITY &ent, VECTOR_2D arcCenter) VECTOR_2D temp, tgtPos // work out position to target to temp = ent.sLocal.vPosition temp.x += ent.vLocalDirection.x * 3000.0 temp.y += ent.vLocalDirection.y * 3000.0 tgtPos = GGSM_GET_CLOSEST_POINT_ON_LINE(arcCenter, ent.sLocal.vPosition, temp, FALSE) GGSM_ENTITY_SET_TARGET_WORLD_VECTOR(ent, tgtpos) // work out radius of arc temp = SUBTRACT_VECTOR_2D(tgtpos, arcCenter) ent.fMoveParam[0] = VECTOR_2D_DIST(tgtPos, arcCenter) // work out first angle point of arc ent.fMoveParam[1] = GET_HEADING_FROM_VECTOR_2D(ent.vLocalDirection.x, ent.vLocalDirection.y) // work out angular speed of arc ent.fMoveParam[2] = (GGSM_ENTITY_GET_SPEED(ent) / (2.0 * GGSM_PI * ent.fMoveParam[0])) SWITCH (ent.eMoveType) CASE GGSM_MOVEMENT_ARC_BASE_LEFT CASE GGSM_MOVEMENT_HALF_ARC_BASE_LEFT ent.fMoveParam[1] += 90.0 ent.fMoveParam[2] *= 1.0 BREAK CASE GGSM_MOVEMENT_ARC_TOP_LEFT CASE GGSM_MOVEMENT_HALF_ARC_TOP_LEFT ent.fMoveParam[1] -= 90.0 ent.fMoveParam[2] *= -1.0 BREAK CASE GGSM_MOVEMENT_ARC_TOP_RIGHT CASE GGSM_MOVEMENT_HALF_ARC_TOP_RIGHT ent.fMoveParam[1] += 90.0 ent.fMoveParam[2] *= 1.0 BREAK CASE GGSM_MOVEMENT_ARC_BASE_RIGHT CASE GGSM_MOVEMENT_HALF_ARC_BASE_RIGHT ent.fMoveParam[1] -= 90.0 ent.fMoveParam[2] *= -1.0 BREAK ENDSWITCH ENDPROC PROC GGSM_ENTITY_MOVE_ARC(GGSM_ENTITY &ent) FLOAT fDelta FLOAT spd = GGSM_ENTITY_GET_SPEED(ent) VECTOR_2D arcCenter = INIT_VECTOR_2D(cfBASE_SCREEN_HALF_WIDTH, cfBASE_SCREEN_HALF_HEIGHT) SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START arcCenter = INIT_VECTOR_2D(cfBASE_SCREEN_HALF_WIDTH, cfBASE_SCREEN_HALF_HEIGHT) GGSM_ENTITY_PRE_CALCULATE_FOR_ARC(ent, arcCenter) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_GOTO_STARTPOS) BREAK CASE GGSM_MOVESTATE_GOTO_STARTPOS IF GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, spd, TRUE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ARC) ent.fDistTravelled = 0 ENDIF BREAK CASE GGSM_MOVESTATE_ARC fDelta = (0 +@ (ent.fMoveParam[2] * 360.0 * sGGSMData.fTimeScale)) ent.fMoveParam[1] += fDelta ent.fDistTravelled += ABSF(fDelta) // rotate round arc center ent.sLocal.vPosition.x = SIN(ent.fMoveParam[1]) * ent.fMoveParam[0] ent.sLocal.vPosition.y = COS(ent.fMoveParam[1]) * ent.fMoveParam[0] // add arc center to local to put it back ent.sLocal.vPosition.x += arcCenter.x ent.sLocal.vPosition.y += arcCenter.y IF (ent.fDistTravelled >= 360.0) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) ENDIF BREAK CASE GGSM_MOVESTATE_ACTIVE spd = 0 +@ GGSM_ENTITY_GET_SPEED(ent) ent.fDistTravelled += spd ent.sLocal.vPosition.x += ent.vLocalDirection.x * spd ent.sLocal.vPosition.y += ent.vLocalDirection.y * spd BREAK ENDSWITCH ENDPROC PROC GGSM_ENTITY_MOVE_ATTACK_KAMAKAZE(GGSM_ENTITY &ent) FLOAT spd FLOAT fDist = 600.0 VECTOR_2D tgtpos = GGSM_GET_TARGET_AT_PLAYER_POSITION() SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START // start ent.fDistTravelled = 0.0 ent.iWeaponBurstCounter = 0 ent.fWeaponTimer = 0 CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) GGSM_ENTITY_SET_WEAPON_STATE(ent, GGSM_WEAPON_STATE_READY) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) BREAK CASE GGSM_MOVESTATE_ACTIVE spd = 0 +@ (GGSM_ENTITY_GET_SPEED(ent) / 2.0) ent.fDistTravelled += spd ent.sLocal.vPosition.x += ent.vLocalDirection.x * spd ent.sLocal.vPosition.y += ent.vLocalDirection.y * spd IF (ent.fDistTravelled > fDist) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) GGSM_ENTITY_FIRE_WEAPON(ent) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ATTACK) ENDIF BREAK CASE GGSM_MOVESTATE_ATTACK IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eMoveFlags, GGSM_ENTITY_BIT_WPN_BURST_FIRED) CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) GGSM_ENTITY_DETACH_FROM_PARENT(ent) GGSM_ENTITY_SET_TARGET_WORLD_VECTOR(ent, tgtpos) IF (ent.eType = GGSM_ENTITY_BANANARED_ATTACK) GGSM_PLAY_SOUND_FROM_POSITION(ARCADE_GAMES_SOUND_GGSM_FLYBY_KAMIKAZE, ent.sWorld.vPosition) GGSM_ENTITY_SET_ANIM_FRAME(ent, 1) ENDIF GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_RAMMING) ENDIF BREAK CASE GGSM_MOVESTATE_RAMMING spd = GGSM_ENTITY_GET_SPEED(ent) * 2.0 IF GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, spd, TRUE) SET_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_COMPLETE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_COMPLETE) ENDIF BREAK CASE GGSM_MOVESTATE_COMPLETE spd = 0 +@ GGSM_ENTITY_GET_SPEED(ent) ent.fDistTravelled += spd ent.sLocal.vPosition.x += ent.vLocalDirection.x * spd ent.sLocal.vPosition.y += ent.vLocalDirection.y * spd BREAK ENDSWITCH ENDPROC PROC GGSM_ENTITY_MOVE_BG_ATTACK(GGSM_ENTITY &ent) FLOAT spd VECTOR_2D tgtPos SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START ent.fDistTravelled = 0 tgtPos.x = ent.sLocal.vPosition.x + (ent.vLocalDirection.x * ent.fMoveParam[0]) tgtPos.y = ent.sLocal.vPosition.y + (ent.vLocalDirection.y * ent.fMoveParam[0]) GGSM_ENTITY_SET_TARGET_LOCAL_VECTOR(ent, tgtPos) ent.sLocal.vScale = INIT_VECTOR_2D(0.5, 0.5) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_NO_COLLISION) CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_GOTO_POS) BREAK CASE GGSM_MOVESTATE_GOTO_POS spd = (GGSM_ENTITY_GET_SPEED(ent) * 0.75) IF GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET_SCALER(ent, spd, ent.fMoveParam[0] / 2.0, TRUE) IF (ent.eType = GGSM_ENTITY_BANANARED_ATTACK) GGSM_PLAY_SOUND_FROM_POSITION(ARCADE_GAMES_SOUND_GGSM_FLYBY_KAMIKAZE, ent.sWorld.vPosition) GGSM_ENTITY_SET_ANIM_FRAME(ent, 1) ELSE GGSM_PLAY_SOUND_FROM_POSITION(ARCADE_GAMES_SOUND_GGSM_FLYBY_UFO, ent.sWorld.vPosition) ENDIF CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_NO_COLLISION) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) GGSM_ENTITY_SET_TARGET_WORLD_VECTOR(ent, GGSM_GET_TARGET_AT_PLAYER_POSITION()) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) ENDIF BREAK CASE GGSM_MOVESTATE_ACTIVE spd = 0 +@ GGSM_ENTITY_GET_SPEED(ent) ent.fDistTravelled += spd ent.sLocal.vPosition.x += (ent.vLocalDirection.x * spd) ent.sLocal.vPosition.y += (ent.vLocalDirection.y * spd) BREAK ENDSWITCH ENDPROC PROC GGSM_ENTITY_MOVE_DESTRUCT_ON_IMPACT(GGSM_ENTITY &ent) SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) BREAK CASE GGSM_MOVESTATE_ACTIVE IF GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, GGSM_ENTITY_GET_SPEED(ent), TRUE) SET_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_COMPLETE) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_SELF_DESTRUCT) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_COMPLETE) ENDIF BREAK CASE GGSM_MOVESTATE_COMPLETE BREAK ENDSWITCH ENDPROC PROC GGSM_ENTITY_MOVE_FOLLOW_PATH(GGSM_ENTITY &ent) FLOAT spd GGSM_PATH_DATA dat SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START ent.fPathValue = 0 SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_REMOVE_WHEN_OFFSCREEN) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_SELECT_POS) BREAK CASE GGSM_MOVESTATE_SELECT_POS dat = GGSM_PATH_DATA_GET(ent.iPathNumber) GGSM_ENTITY_SET_TARGET_WORLD_VECTOR(ent, GGSM_PATH_DATA_GET_POINT(dat, FLOOR(ent.fPathValue))) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_GOTO_POS) BREAK CASE GGSM_MOVESTATE_GOTO_POS spd = GGSM_ENTITY_GET_SPEED(ent) IF NOT GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, spd, TRUE) EXIT ENDIF ent.fPathValue ++ dat = GGSM_PATH_DATA_GET(ent.iPathNumber) IF (ent.fPathValue >= GGSM_PATH_DATA_GET_NUM_POINTS(dat)) SET_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_COMPLETE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) ELSE GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_SELECT_POS) ENDIF BREAK CASE GGSM_MOVESTATE_ACTIVE spd = 0 +@ GGSM_ENTITY_GET_SPEED(ent) ent.fDistTravelled += spd ent.sLocal.vPosition.x += ent.vLocalDirection.x * spd ent.sLocal.vPosition.y += ent.vLocalDirection.y * spd BREAK ENDSWITCH ENDPROC PROC GGSM_ENTITY_MOVE_FOLLOW_REL_PATH(GGSM_ENTITY &ent) FLOAT spd GGSM_PATH_DATA dat VECTOR_2D vBasePos, vRootPoint, vRel SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START ent.fPathValue = 0 SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_REMOVE_WHEN_OFFSCREEN) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_SELECT_POS) BREAK CASE GGSM_MOVESTATE_SELECT_POS dat = GGSM_PATH_DATA_GET(ent.iPathNumber) vBasePos = GGSM_UNPACK_VECTOR_2D(ent.iPackedLocalOrigin) vRootPoint = GGSM_PATH_DATA_GET_POINT(dat, 0) vRel = SUBTRACT_VECTOR_2D(GGSM_PATH_DATA_GET_POINT(dat, FLOOR(ent.fPathValue)), vRootPoint) IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eMoveFlags, GGSM_MOVE_BIT_FLIP_RELATIVE_PATH_X) vRel.x *= -1.0 ENDIF IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eMoveFlags, GGSM_MOVE_BIT_FLIP_RELATIVE_PATH_Y) vRel.y *= -1.0 ENDIF GGSM_ENTITY_SET_TARGET_WORLD_VECTOR(ent, ADD_VECTOR_2D(vBasePos, vRel)) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_GOTO_POS) BREAK CASE GGSM_MOVESTATE_GOTO_POS spd = GGSM_ENTITY_GET_SPEED(ent) IF NOT GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, spd, TRUE) EXIT ENDIF ent.fPathValue ++ dat = GGSM_PATH_DATA_GET(ent.iPathNumber) IF (ent.fPathValue >= GGSM_PATH_DATA_GET_NUM_POINTS(dat)) SET_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_COMPLETE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) ELSE GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_SELECT_POS) ENDIF BREAK CASE GGSM_MOVESTATE_ACTIVE spd = 0 +@ GGSM_ENTITY_GET_SPEED(ent) ent.fDistTravelled += spd ent.sLocal.vPosition.x += ent.vLocalDirection.x * spd ent.sLocal.vPosition.y += ent.vLocalDirection.y * spd BREAK ENDSWITCH ENDPROC PROC GGSM_ENTITY_MOVE_FORWARD_THEN_BACK(GGSM_ENTITY &ent) VECTOR_2D tgtPos FLOAT spd SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START tgtPos = ent.sLocal.vPosition tgtPos.x += (ent.vLocalDirection.x * ent.fMoveParam[0]) tgtPos.y += (ent.vLocalDirection.y * ent.fMoveParam[0]) CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) GGSM_ENTITY_SET_TARGET_LOCAL_VECTOR(ent, tgtpos) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_GOTO_STARTPOS) BREAK CASE GGSM_MOVESTATE_GOTO_STARTPOS spd = GGSM_ENTITY_GET_SPEED(ent) IF GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, spd, TRUE) GGSM_ENTITY_FIRE_WEAPON(ent) ent.vLocalDirection.x *= -1.0 ent.vLocalDirection.y *= -1.0 GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) ENDIF BREAK CASE GGSM_MOVESTATE_ACTIVE spd = 0 +@ GGSM_ENTITY_GET_SPEED(ent) ent.fDistTravelled += spd ent.sLocal.vPosition.x += ent.vLocalDirection.x * spd ent.sLocal.vPosition.y += ent.vLocalDirection.y * spd IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_ON_SCREEN) SET_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_COMPLETE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_COMPLETE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_ENTITY_MOVE_HALF_ARC(GGSM_ENTITY &ent) FLOAT fDelta FLOAT spd = GGSM_ENTITY_GET_SPEED(ent) VECTOR_2D arcCenter SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START arcCenter = INIT_VECTOR_2D(cfBASE_SCREEN_HALF_WIDTH, cfBASE_SCREEN_HALF_HEIGHT) GGSM_ENTITY_PRE_CALCULATE_FOR_ARC(ent, arcCenter) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_GOTO_STARTPOS) BREAK CASE GGSM_MOVESTATE_GOTO_STARTPOS IF GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, spd, TRUE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ARC) ent.fDistTravelled = 0 ENDIF BREAK CASE GGSM_MOVESTATE_ARC fDelta = (0 +@ (ent.fMoveParam[2] * 360.0 * sGGSMData.fTimeScale)) ent.fMoveParam[1] += fDelta ent.fDistTravelled += ABSF(fDelta) // rotate round arc center ent.sLocal.vPosition.x = SIN(ent.fMoveParam[1]) * ent.fMoveParam[0] ent.sLocal.vPosition.y = COS(ent.fMoveParam[1]) * ent.fMoveParam[0] // add arc center to local to put it back ent.sLocal.vPosition.x += arcCenter.x ent.sLocal.vPosition.y += arcCenter.y IF (ent.fDistTravelled >= 180.0) ent.vLocalDirection.x *= -1.0 ent.vLocalDirection.y *= -1.0 GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) ENDIF BREAK CASE GGSM_MOVESTATE_ACTIVE spd = 0 +@ GGSM_ENTITY_GET_SPEED(ent) ent.fDistTravelled += spd ent.sLocal.vPosition.x += ent.vLocalDirection.x * spd ent.sLocal.vPosition.y += ent.vLocalDirection.y * spd BREAK ENDSWITCH ENDPROC PROC GGSM_ENTITY_MOVE_KAMAKAZE(GGSM_ENTITY &ent) FLOAT spd FLOAT fDist = 600.0 VECTOR_2D tgtpos = GGSM_GET_TARGET_AT_PLAYER_POSITION() SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START // start ent.fDistTravelled = 0.0 GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) BREAK CASE GGSM_MOVESTATE_ACTIVE spd = 0 +@ GGSM_ENTITY_GET_SPEED(ent) ent.fDistTravelled += spd ent.sLocal.vPosition.x += ent.vLocalDirection.x * spd ent.sLocal.vPosition.y += ent.vLocalDirection.y * spd IF (VECTOR_2D_DIST2(tgtpos, ent.sWorld.vPosition) < (fDist * fDist)) GGSM_ENTITY_DETACH_FROM_PARENT(ent) GGSM_ENTITY_SET_TARGET_WORLD_VECTOR(ent, tgtpos) IF (ent.eType = GGSM_ENTITY_BANANARED_ATTACK) GGSM_PLAY_SOUND_FROM_POSITION(ARCADE_GAMES_SOUND_GGSM_FLYBY_KAMIKAZE, ent.sWorld.vPosition) GGSM_ENTITY_SET_ANIM_FRAME(ent, 1) ENDIF GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_RAMMING) ENDIF BREAK CASE GGSM_MOVESTATE_RAMMING spd = GGSM_ENTITY_GET_SPEED(ent) * 2.0 IF GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, spd, TRUE) SET_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_COMPLETE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_COMPLETE) ENDIF BREAK CASE GGSM_MOVESTATE_COMPLETE spd = 0 +@ GGSM_ENTITY_GET_SPEED(ent) ent.fDistTravelled += spd ent.sLocal.vPosition.x += ent.vLocalDirection.x * spd ent.sLocal.vPosition.y += ent.vLocalDirection.y * spd BREAK ENDSWITCH ENDPROC PROC GGSM_ENTITY_MOVE_ORBIT(GGSM_ENTITY &ent) VECTOR_2D tmp SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START // start ent.eMoveState = GGSM_MOVESTATE_ACTIVE tmp.x = SIN(ent.fMoveParam[1]) * ent.fMoveParam[0] tmp.y = COS(ent.fMoveParam[1]) * ent.fMoveParam[0] GGSM_ENTITY_SET_TARGET_LOCAL_VECTOR(ent, tmp) IF (VECTOR_2D_DIST(ADD_VECTOR_2D(tmp, ent.sLocal.vPosition), ent.sLocal.vPosition) < 2) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) ELSE GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_GOTO_STARTPOS) ENDIF BREAK CASE GGSM_MOVESTATE_GOTO_STARTPOS IF GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, GGSM_ENTITY_GET_SPEED(ent), TRUE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) ENDIF BREAK CASE GGSM_MOVESTATE_ACTIVE // fMoveParam0 is the distance from center // fMoveParam1 is the angle around the center // fMoveParam2 is revolutions per second ent.fMoveParam[1] += (0 +@ (ent.fMoveParam[2] * 360.0 * sGGSMData.fTimeScale)) ent.sLocal.vPosition.x = SIN(ent.fMoveParam[1]) * ent.fMoveParam[0] ent.sLocal.vPosition.y = COS(ent.fMoveParam[1]) * ent.fMoveParam[0] ent.vLocalDirection = NORMALISE_VECTOR_2D(ent.sLocal.vPosition) IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eMoveFlags, GGSM_MOVE_BIT_ROTATE_TO_FACE_DIRECTION) ent.sLocal.fRotation = GET_HEADING_FROM_VECTOR_2D(ent.sLocal.vPosition.x, ent.sLocal.vPosition.y) - ent.sLocal.fRotation ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_ENTITY_MOVE_TO_VECTOR(GGSM_ENTITY &ent) SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_GOTO_POS) BREAK CASE GGSM_MOVESTATE_GOTO_POS IF (ent.fMoveTimer >= ent.fMoveParam[0]) IF GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, GGSM_ENTITY_GET_SPEED(ent), TRUE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) ENDIF ENDIF BREAK CASE GGSM_MOVESTATE_ACTIVE IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_WPN_FIRE_ON_ARRIVE) SET_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_COMPLETE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_COMPLETE) EXIT ENDIF GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ATTACK) BREAK CASE GGSM_MOVESTATE_ATTACK IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eMoveFlags, GGSM_ENTITY_BIT_WPN_BURST_FIRED) SET_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_COMPLETE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_COMPLETE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_ENTITY_MOVE_ROTATE_FACE_TO_VECTOR(GGSM_ENTITY &ent) VECTOR_2D dir FLOAT fAngle VECTOR_2D localTgtPos = GGSM_UNPACK_VECTOR_2D(ent.iPackedLocalTargetPosition) SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_GOTO_POS) BREAK CASE GGSM_MOVESTATE_GOTO_POS IF (ent.fMoveTimer >= ent.fMoveParam[0]) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) ENDIF BREAK CASE GGSM_MOVESTATE_ACTIVE dir = SUBTRACT_VECTOR_2D(localTgtPos, ent.sLocal.vPosition) fAngle = GET_HEADING_FROM_VECTOR_2D(dir.x, dir.y) - ent.sLocal.fRotation IF (fAngle > 180.0) fAngle -= 360.0 ENDIF IF (fAngle < -180.0) fAngle += 360.0 ENDIF ent.sLocal.fRotation += (0 +@ fAngle) IF (ABSF(fAngle) < 1.0) ent.sLocal.fRotation = GET_HEADING_FROM_VECTOR_2D(dir.x, dir.y) SET_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_COMPLETE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_COMPLETE) ENDIF BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Player controlled entity. /// PARAMS: /// ent - PROC GGSM_ENTITY_MOVE_PLAYER_CONTROLLED(GGSM_ENTITY &ent) FLOAT spd = 0 +@ GGSM_ENTITY_GET_SPEED(ent) FLOAT hw, hh GGSM_ENTITY_DATA entData = GGSM_ENTITY_DATA_GET(ent.eType) VECTOR_2D sprsize = GGSM_GET_SPRITE_SIZE(entData.eSpriteType) VECTOR_2D oldPos = ent.sLocal.vPosition CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START // start IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.eStageFlags, GGSM_STAGE_BIT_STAGE_STARTED) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_STAGE_STARTED) ENDIF ent.sLocal.vPosition.x = 200.0 ent.sLocal.vPosition.y = 540.0 ent.vLocalDirection.x = 1.0 ent.vLocalDirection.y = 0.0 GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_PLYR_INVUNERABLE) GGSM_ENTITY_SET_ANIM_FRAME(ent, 0) BREAK CASE GGSM_MOVESTATE_PLYR_INVUNERABLE // move straight until at ready posF GGSM_ENTITY_SET_ANIM_FRAME(ent, 0) ent.iInvTimeMS = GET_GAME_TIMER() + GGSM_PLAYER_INITIAL_INV_TIME ent.sLocal.vPosition.x += (spd / 2.0) IF (ent.sLocal.vPosition.x > 600.0) ent.sLocal.vPosition.x = 600.0 GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_PLYR_DIALOG) ENDIF BREAK CASE GGSM_MOVESTATE_PLYR_DIALOG GGSM_ENTITY_SET_ANIM_FRAME(ent, 0) ent.iInvTimeMS = GET_GAME_TIMER() + GGSM_PLAYER_INITIAL_INV_TIME IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.eStageFlags, GGSM_STAGE_BIT_INTRO_DONE) IF (sGGSMData.sGameStats.level = 1) //GGSM_DIALOG_CONTROLLER_START_DIALOG(sGGSMData.sDialogController, GGSM_DIALOG_ASTEROID_ENTER) ENDIF SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_INTRO_DONE) ENDIF GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_PLYR_DIALOG_DONE) BREAK CASE GGSM_MOVESTATE_PLYR_DIALOG_DONE // move straight until at ready posF GGSM_ENTITY_SET_ANIM_FRAME(ent, 0) ent.iInvTimeMS = GET_GAME_TIMER() + GGSM_PLAYER_INITIAL_INV_TIME GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) BREAK CASE GGSM_MOVESTATE_ACTIVE // allow player cntrol // allow for right stick control. IF GGSM_ALTER_POINT_WITH_INPUT(ent.sLocal.vPosition, GGSM_ENTITY_GET_SPEED(ent)) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eHelpFlags, GGSM_HELP_BIT_MOVE) ELIF GGSM_ALTER_POINT_WITH_INPUT(ent.sLocal.vPosition, GGSM_ENTITY_GET_SPEED(ent), GGSM_INPUT_RSTICK) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eHelpFlags, GGSM_HELP_BIT_MOVE) ELIF GGSM_ALTER_POINT_WITH_INPUT(ent.sLocal.vPosition, GGSM_ENTITY_GET_SPEED(ent), GGSM_INPUT_DPAD) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eHelpFlags, GGSM_HELP_BIT_MOVE) ENDIF // clamp movement hw = sprsize.x / 2.0 hh = sprsize.y / 2.0 ent.sLocal.vPosition.x = CLAMP(ent.sLocal.vPosition.x, 340.0 + hw, 1590.0 - hw) ent.sLocal.vPosition.y = CLAMP(ent.sLocal.vPosition.y, 90.0 + hh, 990.0 - hh) // handle movement anim IF (ent.eType = GGSM_ENTITY_PLAYERSHIP) IF (ent.sLocal.vPosition.y - oldPos.y < 0) GGSM_ENTITY_SET_ANIM_FRAME(ent, 1) ELIF (ent.sLocal.vPosition.y - oldPos.y > 0) GGSM_ENTITY_SET_ANIM_FRAME(ent, 2) ELSE GGSM_ENTITY_SET_ANIM_FRAME(ent, 0) ENDIF ENDIF IF (GET_GAME_TIMER() > sGGSMData.iLastMonkeyFireSoundTimeMS) IF GGSM_HAS_PLAYER_PRESSED_FIRE() IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.eStageFlags, GGSM_STAGE_BIT_DISABLE_WEAPONS) GGSM_PLAY_SOUND_FROM_POSITION(ARCADE_GAMES_SOUND_GGSM_MONKEY_VOICE_FIRE, ent.sWorld.vPosition) sGGSMData.iLastMonkeyFireSoundTimeMS = (GET_GAME_TIMER() + GET_RANDOM_INT_IN_RANGE(3000, 6000)) ENDIF ENDIF ENDIF IF GGSM_HAS_PLAYER_HOLDING_FIRE() SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eHelpFlags, GGSM_HELP_BIT_SHOOT) ENDIF IF GGSM_HAS_PLAYER_PRESSED_DEFENSE_WEAPON() IF (sGGSMData.eWeaponSlot[GGSM_WEAPON_SLOT_DEFENSE] != GGSM_SPRITE_NONE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_PLAYER_DEFENSE_WPN_USED) ELSE GGSM_PLAY_SOUND(ARCADE_GAMES_SOUND_GGSM_PICKUP_UNAVAILABLE) ENDIF ENDIF IF (ent.fTimer > 1.0) IF GGSM_SHOULD_SHOW_TUTORIAL(GGSM_HELP_BIT_MOVE) ARCADE_GAMES_HELP_TEXT_PRINT(ARCADE_GAMES_HELP_TEXT_ENUM_GGSM_MOVESHIP) ENDIF SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eHelpFlags, GGSM_HELP_BIT_MOVE) ENDIF IF (ent.fTimer > 4.0) IF GGSM_SHOULD_SHOW_TUTORIAL(GGSM_HELP_BIT_SHOOT) ARCADE_GAMES_HELP_TEXT_CLEAR() ARCADE_GAMES_HELP_TEXT_PRINT(ARCADE_GAMES_HELP_TEXT_ENUM_GGSM_FIREWEAPONS) ENDIF SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eHelpFlags, GGSM_HELP_BIT_SHOOT) ENDIF IF GGSM_HAS_PLAYER_PRESSED_SPECIAL_WEAPON() IF (sGGSMData.eWeaponSlot[GGSM_WEAPON_SLOT_SPECIAL] != GGSM_SPRITE_NONE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_PLAYER_SPECIAL_WPN_USED) ELSE GGSM_PLAY_SOUND(ARCADE_GAMES_SOUND_GGSM_PICKUP_UNAVAILABLE) ENDIF ENDIF BREAK ENDSWITCH ENDPROC /// PURPOSE: /// Player controlled entity. /// PARAMS: /// ent - PROC GGSM_ENTITY_MOVE_RANDOM_WANDER(GGSM_ENTITY &ent) VECTOR_2D tmp SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START // start ent.eMoveState = GGSM_MOVESTATE_SELECT_POS BREAK CASE GGSM_MOVESTATE_SELECT_POS IF (ent.fMoveTimer >= ent.fMoveParam[0]) tmp.x = GET_RANDOM_FLOAT_IN_RANGE(GGSM_PX_OVERSCAN_MIN_X + 100, GGSM_PX_OVERSCAN_MAX_X - 100) tmp.y = GET_RANDOM_FLOAT_IN_RANGE(GGSM_PX_OVERSCAN_MIN_Y + 100, GGSM_PX_OVERSCAN_MAX_Y - 100) GGSM_ENTITY_SET_TARGET_WORLD_VECTOR(ent, tmp) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) ENDIF BREAK CASE GGSM_MOVESTATE_ACTIVE IF GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, GGSM_ENTITY_GET_SPEED(ent), TRUE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_SELECT_POS) ENDIF IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(ent.eMoveFlags, GGSM_MOVE_BIT_FORCE_MOVEMENT_TO_END) EXIT ENDIF IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eMoveFlags, GGSM_MOVE_BIT_TO_ORIGIN_ON_MOVE_ABORT) GGSM_ENTITY_SET_TARGET_LOCAL_VECTOR(ent, GGSM_UNPACK_VECTOR_2D(ent.iPackedLocalOrigin)) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_GOTO_ORIGIN) ELSE GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_COMPLETE) ENDIF BREAK CASE GGSM_MOVESTATE_GOTO_ORIGIN IF GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, GGSM_ENTITY_GET_SPEED(ent), TRUE) SET_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_COMPLETE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_COMPLETE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_ENTITY_MOVE_SINWAVE(GGSM_ENTITY &ent) FLOAT fPeriod FLOAT spd = 0 +@ GGSM_ENTITY_GET_SPEED(ent) SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START // start ent.iPackedLocalOrigin = GGSM_PACK_VECTOR_2D_TO_INT(ent.sLocal.vPosition) ent.fDistTravelled = 0.0 // move param 0 is the period length - movement needed to 1 wave IF (ent.fMoveParam[0] = 0.0) ent.fMoveParam[0] = 600.0 ENDIF // move param 1 is the height of the wave IF (ent.fMoveParam[1] = 0.0) ent.fMoveParam[1] = 88.0 ENDIF GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) BREAK CASE GGSM_MOVESTATE_ACTIVE ent.fDistTravelled += spd // move forward ent.sLocal.vPosition = GGSM_UNPACK_VECTOR_2D(ent.iPackedLocalOrigin) ent.sLocal.vPosition.x += (ent.vLocalDirection.x * ent.fDistTravelled) ent.sLocal.vPosition.y += (ent.vLocalDirection.y * ent.fDistTravelled) // horizontal displacement - get the perpendicular fPeriod = TO_FLOAT(FLOOR(ent.fDistTravelled) % FLOOR(ent.fMoveParam[0])) / ent.fMoveParam[0] spd = SIN(fPeriod * 360.0) * ent.fMoveParam[1] ent.sLocal.vPosition.x += (ent.vLocalDirection.y * spd) ent.sLocal.vPosition.y += (ent.vLocalDirection.x * spd) BREAK ENDSWITCH ENDPROC PROC GGSM_ENTITY_MOVE_SNAKESECTION(GGSM_ENTITY &ent) VECTOR_2D dir VECTOR_2D parentPos VECTOR_2D desiredPos INT iParent = GGSM_ENTITY_GET_PARENT_INDEX(ent) SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START // start SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_REMOVE_WHEN_OFFSCREEN) SET_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_POSITION_OVERRIDE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) BREAK ENDSWITCH IF (iParent = GGSM_INVALID_ENTITY) EXIT ENDIF IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(ent.eMoveFlags, GGSM_MOVE_BIT_POSITION_OVERRIDE) EXIT ENDIF parentPos = sGGSMData.sEntities[iParent].sWorld.vPosition dir.x = parentPos.x - ent.sWorld.vPosition.x dir.y = parentPos.y - ent.sWorld.vPosition.y ent.vLocalDirection = NORMALISE_VECTOR_2D(dir) desiredPos.x = parentPos.x - (ent.sLocal.vPosition.x * ent.vLocalDirection.x) desiredPos.y = parentPos.y - (ent.sLocal.vPosition.x * ent.vLocalDirection.y) ent.sWorld.vPosition = LERP_VECTOR_2D(ent.sWorld.vPosition, desiredPos, 0.5) IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eMoveFlags, GGSM_MOVE_BIT_ROTATE_TO_FACE_DIRECTION) ent.sWorld.fRotation = GET_HEADING_FROM_VECTOR_2D(ent.vLocalDirection.x, ent.vLocalDirection.y) ENDIF ENDPROC /// PURPOSE: /// Simple Movestraight function /// PARAMS: /// ent - /// RETURNS: /// Returns true when entity has left the play field PROC GGSM_ENTITY_MOVE_STRAIGHT(GGSM_ENTITY &ent) FLOAT spd = 0 +@ GGSM_ENTITY_GET_SPEED(ent) IF (ent.eMoveState = GGSM_MOVESTATE_START) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_REMOVE_WHEN_OFFSCREEN) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) ENDIF ent.fDistTravelled += spd ent.sLocal.vPosition.x += ent.vLocalDirection.x * spd ent.sLocal.vPosition.y += ent.vLocalDirection.y * spd ENDPROC /// PURPOSE: /// Player controlled entity. /// PARAMS: /// ent - PROC GGSM_ENTITY_MOVE_TARGETTED_WANDER(GGSM_ENTITY &ent) SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START // start GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_SELECT_POS) BREAK CASE GGSM_MOVESTATE_SELECT_POS IF (ent.fMoveTimer >= ent.fMoveParam[0]) GGSM_ENTITY_SET_TARGET_WORLD_VECTOR(ent, GGSM_GET_TARGET_AT_PLAYER_POSITION()) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) ENDIF BREAK CASE GGSM_MOVESTATE_ACTIVE IF GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, GGSM_ENTITY_GET_SPEED(ent), TRUE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_SELECT_POS) ENDIF IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(ent.eMoveFlags, GGSM_MOVE_BIT_FORCE_MOVEMENT_TO_END) EXIT ENDIF IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eMoveFlags, GGSM_MOVE_BIT_TO_ORIGIN_ON_MOVE_ABORT) GGSM_ENTITY_SET_TARGET_LOCAL_VECTOR(ent, GGSM_UNPACK_VECTOR_2D(ent.iPackedLocalOrigin)) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_GOTO_ORIGIN) ELSE GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_COMPLETE) ENDIF BREAK CASE GGSM_MOVESTATE_GOTO_ORIGIN IF GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, GGSM_ENTITY_GET_SPEED(ent), TRUE) SET_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_COMPLETE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_COMPLETE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_ENTITY_MOVE_MIDDLE_Y_RANGE(GGSM_ENTITY &ent) VECTOR_2D tgtPos SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START // start GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_GOTO_POS) GGSM_ENTITY_SET_TARGET_WORLD_VECTOR(ent, INIT_VECTOR_2D(1225.0, 540.0)) BREAK CASE GGSM_MOVESTATE_GOTO_POS IF GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, GGSM_ENTITY_GET_SPEED(ent), TRUE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_SELECT_POS) ENDIF BREAK CASE GGSM_MOVESTATE_SELECT_POS tgtPos = ent.sWorld.vPosition tgtPos.y = GET_RANDOM_FLOAT_IN_RANGE(370.0, 762.0) GGSM_ENTITY_SET_TARGET_WORLD_VECTOR(ent, tgtPos) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) BREAK CASE GGSM_MOVESTATE_ACTIVE IF GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, GGSM_ENTITY_GET_SPEED(ent), TRUE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_SELECT_POS) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_ENTITY_MOVE_TRACK_PLAYER_Y(GGSM_ENTITY &ent) FLOAT spd VECTOR_2D tgtPos = GGSM_GET_TARGET_AT_PLAYER_POSITION() SWITCH (ent.eMoveState) CASE GGSM_MOVESTATE_START // start GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_GOTO_POS) GGSM_ENTITY_SET_TARGET_WORLD_VECTOR(ent, INIT_VECTOR_2D(1225.0, 540.0)) BREAK CASE GGSM_MOVESTATE_GOTO_POS IF GGSM_ENTITY_UPDATE_MOVEMENT_TO_TARGET(ent, GGSM_ENTITY_GET_SPEED(ent), TRUE) GGSM_ENTITY_SET_MOVEMENT_STATE(ent, GGSM_MOVESTATE_ACTIVE) ENDIF BREAK CASE GGSM_MOVESTATE_ACTIVE spd = 0 +@ GGSM_ENTITY_GET_SPEED(ent) ent.fDistTravelled += spd ent.sLocal.vPosition.x += ent.vLocalDirection.x * spd ent.sLocal.vPosition.y += ent.vLocalDirection.y * spd IF (ABSF(ent.sWorld.vPosition.y - tgtPos.y) > 30.0) IF (ent.sWorld.vPosition.y < tgtPos.y) ent.vLocalDirection = INIT_VECTOR_2D(0, 1) ELSE ent.vLocalDirection = INIT_VECTOR_2D(0, -1) ENDIF ELSE ent.vLocalDirection = INIT_VECTOR_2D(0, 0) ENDIF BREAK ENDSWITCH ENDPROC //------------------------------------------------- // ENTITY FUNCTIONS //------------------------------------------------- FUNC BOOL GGSM_ENTITY_IS_AT_FULL_HEALTH(GGSM_ENTITY &ent) GGSM_ENTITY_DATA dat = GGSM_ENTITY_DATA_GET(ent.eType) RETURN (ent.iHP >= dat.iMaxHP) ENDFUNC PROC GGSM_ENTITY_RESET_HEALTH(GGSM_ENTITY &ent) GGSM_ENTITY_DATA dat = GGSM_ENTITY_DATA_GET(ent.eType) ent.iHP = dat.iMaxHP ENDPROC /// PURPOSE: /// Resets an Entity to default PROC GGSM_ENTITY_RESET(GGSM_ENTITY &ent) ent.eType = GGSM_ENTITY_INVALID ent.eState = GGSM_ENTITY_STATE_NONE ent.eFlags = GGSM_ENTITY_BIT_NONE ent.fExplodeTimer = 0.0 ent.iHP = 0 ent.eSpriteAnim = GGSM_SPRITE_ANIM_NONE ent.fTimer = 0.0 ent.fAnimFrame = 0.0 GGSM_IDENTITY_TRANSFORM(ent.sLocal) GGSM_IDENTITY_TRANSFORM(ent.sWorld) GGSM_ENTITY_SET_PARENT_INDEX(ent, GGSM_INVALID_GROUP_ID) ent.iGroupID = GGSM_INVALID_GROUP_ID ent.eMoveFlags = GGSM_MOVE_BIT_NONE ent.iPackedLocalTargetPosition = 0 GGSM_ENTITY_CLEAR_Z_DEPTH(ent) ent.fDistTravelled = 0 ENDPROC /// PURPOSE: /// Resets the entity array /// PARAMS: /// eType - Type this is used for collison type things /// array - PROC GGSM_RESET_ENTITY_ARRAY(GGSM_ENTITY &array[]) INT i REPEAT COUNT_OF(array) i GGSM_ENTITY_RESET(array[i]) GGSM_ENTITY_SET_ARRAY_INDEX(array[i], i) ENDREPEAT ENDPROC PROC GGSM_ENTITY_SET_STATE(GGSM_ENTITY &ent, GGSM_ENTITY_STATE eState) CDEBUG1LN(DEBUG_MINIGAME, "GGSM_ENTITY_SET_STATE - TYPE:", GGSM_ENTITY_TYPE_TO_STRING(ent.eType), " ARRAY INDEX:", GGSM_ENTITY_GET_ARRAY_INDEX(ent), " STATE:", GGSM_ENTITY_STATE_TO_STRING(eState)) ent.eState = eState ent.fTimer = 0 ENDPROC /// PURPOSE: /// Destroy Entity /// PARAMS: /// ent - PROC GGSM_ENTITY_DESTROY(GGSM_ENTITY &ent) INT iArrayIndex = GGSM_ENTITY_GET_ARRAY_INDEX(ent) IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_FORCE_SCROLLING_TO_STOP) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_BRING_CAMERA_TO_STOP) ENDIF GGSM_REMOVE_ENTITY_FROM_GROUP(ent) GGSM_ENTITY_CLEAR_Z_DEPTH(ent) ent.eFlags = GGSM_ENTITY_BIT_NONE ent.eState = GGSM_ENTITY_STATE_NONE CDEBUG1LN(DEBUG_MINIGAME, "GGSM_ENTITY_DESTROY - IND:", iArrayIndex, " TYPE: ", GGSM_ENTITY_TYPE_TO_STRING(ent.eType)) IF (iArrayIndex = sGGSMData.iPlayerShipIndex) sGGSMData.iPlayerShipIndex = GGSM_INVALID_ENTITY ENDIF IF (iArrayIndex = sGGSMData.iPlayerDecoyIndex) sGGSMData.iPlayerDecoyIndex = GGSM_INVALID_ENTITY ENDIF IF (iArrayIndex = sGGSMData.iPlayerShieldIndex) sGGSMData.iPlayerShieldIndex = GGSM_INVALID_ENTITY ENDIF GGSM_ENTITY_RESET(ent) ENDPROC PROC GGSM_ENTITY_ATTACH_TO_PARENT(GGSM_ENTITY &ent, GGSM_ENTITY &parent, BOOL bJoinParentGroup = TRUE) GGSM_ENTITY_SET_PARENT_INDEX(ent, GGSM_ENTITY_GET_ARRAY_INDEX(parent)) GGSM_TRANSFORM_WORLD_TO_LOCAL(parent.sWorld, ent.sWorld, ent.sLocal) IF (bJoinParentGroup = TRUE) IF (parent.iGroupID != GGSM_INVALID_GROUP_ID) AND (parent.iGroupID != ent.iGroupID) GGSM_REMOVE_ENTITY_FROM_GROUP(ent) GGSM_ADD_ENTITY_TO_GROUP(ent, parent.iGroupID) ENDIF ENDIF UNUSED_PARAMETER(bJoinParentGroup) ENDPROC /// PURPOSE: /// Updates the on screen checks /// PARAMS: /// ent - /// RETURNS: /// returns true if the offscreen checks say we should be deleted FUNC BOOL GGSM_ENTITY_UPDATE_SCREEN_CHECKS(GGSM_ENTITY &ent) INT iArrayIndex = GGSM_ENTITY_GET_ARRAY_INDEX(ent) IF NOT GGSM_IS_COLLIDER_AABB_ON_SCREEN(ent.sCollider) CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_ON_SCREEN) IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_REMOVE_WHEN_OFFSCREEN) RETURN FALSE ENDIF IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_ENTERED_PLAYFIELD) RETURN FALSE ENDIF IF (ent.iGroupID = GGSM_INVALID_GROUP_ID) RETURN TRUE ENDIF IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntityGroup[ent.iGroupID].eFlags, GGSM_GROUP_BIT_ALLOW_OFFSCREEN) RETURN FALSE ENDIF CLEAR_BIT(sGGSMData.sEntityGroup[ent.iGroupID].iMembersOnStageBitSet, iArrayIndex) IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntityGroup[ent.iGroupID].eFlags, GGSM_GROUP_BIT_END_WHEN_ALL_OFFSCREEN) RETURN (sGGSMData.sEntityGroup[ent.iGroupID].iMembersOnStageBitSet = 0) ENDIF ELSE SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_ON_SCREEN) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_ENTERED_PLAYFIELD) IF (ent.iGroupID != GGSM_INVALID_GROUP_ID) SET_BIT(sGGSMData.sEntityGroup[ent.iGroupID].iMembersOnStageBitSet, iArrayIndex) ENDIF ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Explode Entity /// PARAMS: /// ent - PROC GGSM_ENTITY_EXPLODE(GGSM_ENTITY &ent) IF (ent.eState != GGSM_ENTITY_STATE_ALIVE) AND (ent.eState != GGSM_ENTITY_STATE_UNDEAD) EXIT ENDIF INT n, sc INT iArrayIndex = GGSM_ENTITY_GET_ARRAY_INDEX(ent) INT iGroupID = GGSM_ENTITY_GET_GROUP_ID(ent) INT iParent = GGSM_ENTITY_GET_PARENT_INDEX(ent) BOOL bIsAllied = IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_IS_PLAYER_ALLIED) CDEBUG1LN(DEBUG_MINIGAME, "GGSM_ENTITY_EXPLODE - TYPE:", GGSM_ENTITY_TYPE_TO_STRING(ent.eType), " ARRAY INDEX:", iArrayIndex) ent.fTimer = 0 // some enemies shoot when they die IF NOT bIsAllied IF (ent.eType = GGSM_ENTITY_CHERRYBOMB) GGSM_PROJECTILE_CREATE_ENEMY_RADIAL_SPREAD(GGSM_PROJECTILE_ENEMY_SHOT, ent.sWorld.vPosition, GET_RANDOM_INT_IN_RANGE(5, 8), GET_RANDOM_FLOAT_IN_RANGE(0, 360), FALSE) ELIF (ent.eType = GGSM_ENTITY_PEANUT_METEOR) GGSM_PROJECTILE_CREATE_ENEMY_CONE_SPREAD(GGSM_PROJECTILE_ENEMY_SHOT, ent.sWorld.vPosition, 90.0, 3, TRUE) ENDIF IF (sGGSMData.bHardMode) GGSM_PROJECTILE_CREATE_ENEMY_RADIAL_SPREAD(GGSM_PROJECTILE_ENEMY_SHOT, ent.sWorld.vPosition, GET_RANDOM_INT_IN_RANGE(1, 6), 0.0, TRUE) ENDIF IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_NO_TAKEDOWN_BONUS) sGGSMData.iEnemiesDestroyed ++ sGGSMData.sGameStats.kills ++ sGGSMData.fChainMultiplier ++ IF (sGGSMData.fChainMultiplier > GGSM_CHAIN_MAX) sGGSMData.fChainMultiplier = GGSM_CHAIN_MAX ENDIF sGGSMData.iKillStreak ++ sGGSMData.fKillStreakTimer = GGSM_TIME_FOR_KILL_STREAK IF GGSM_DOES_PLAYER_SHIP_EXIST() IF (sGGSMData.iKillStreak >= GGSM_KILLS_NEEDED_FOR_KILL_STREAK) GGSM_PLAY_SOUND_FROM_POSITION(ARCADE_GAMES_SOUND_GGSM_MONKEY_VOICE_KILL_STREAK, sGGSMData.sEntities[sGGSMData.iPlayerShipIndex].sWorld.vPosition) sGGSMData.iKillStreak = 0 ENDIF ENDIF ENDIF sGGSMData.iLastEnemyDeathTimeMS = GET_GAME_TIMER() IF (FLOOR(sGGSMData.fChainMultiplier) > 1) sc = FLOOR(TO_FLOAT(GGSM_ENTITY_GET_SCORE_FROM_TYPE(ent.eType)) * FLOOR(sGGSMData.fChainMultiplier)) ELSE sc = GGSM_ENTITY_GET_SCORE_FROM_TYPE(ent.eType) ENDIF GGSM_INCREASE_PLAYER_SCORE(sc) ENDIF // relink sections IF (iGroupID != GGSM_INVALID_GROUP_ID) AND (sGGSMData.sEntityGroup[iGroupID].iLeader = iArrayIndex) IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntityGroup[iGroupID].eFlags, GGSM_GROUP_BIT_DIE_WHEN_LEADER_DIES) REPEAT GGSM_MAX_ENTITIES n IF (n != iArrayIndex) AND (GGSM_ENTITY_GET_GROUP_ID(sGGSMData.sEntities[n]) = iGroupID) IF (sGGSMData.sEntities[n].eState = GGSM_ENTITY_STATE_UNDEAD) GGSM_ENTITY_SET_STATE(sGGSMData.sEntities[n], GGSM_ENTITY_STATE_ALIVE) ENDIF GGSM_ENTITY_EXPLODE(sGGSMData.sEntities[n]) ENDIF ENDREPEAT ENDIF ENDIF REPEAT GGSM_MAX_ENTITIES n IF GGSM_ENTITY_GET_PARENT_INDEX(sGGSMData.sEntities[n]) = iArrayIndex GGSM_ENTITY_SET_PARENT_INDEX(sGGSMData.sEntities[n], iParent) IF (iParent = GGSM_INVALID_ENTITY) sGGSMData.sEntities[n].sLocal = sGGSMData.sEntities[n].sWorld ENDIF ENDIF ENDREPEAT GGSM_REMOVE_ENTITY_FROM_GROUP(ent) ent.iInvTimeMS = -HIGHEST_INT CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_TOOK_DAMAGE_THIS_FRAME) // if i'm the player IF (iArrayIndex = sGGSMData.iPlayerShipIndex) sGGSMData.iNoMissBonus = 0 sGGSMData.iNoDamageBonus = 0 sGGSMData.fChainMultiplier = 0.0 sGGSMData.fTimeScale = 1.0 GGSM_DESTROY_ALL_FACTION_BULLETS(sGGSMData.sProjectiles, TRUE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_PLAYER_DIED) SET_CONTROL_SHAKE(FRONTEND_CONTROL, 300, 100) IF (sGGSMData.iPlayerLives > 0) sGGSMData.iPlayerLives -- ENDIF sGGSMData.bGrazed = FALSE IF (sGGSMData.iPlayerLives = 0) GGSM_PLAY_AVATAR_GAME_OVER_ANIM() ELSE GGSM_PLAY_AVATAR_LOST_LIFE_ANIM() ENDIF ENDIF GGSM_ENTITY_SET_STATE(ent, GGSM_ENTITY_STATE_EXPLODING) ENDPROC /// PURPOSE: /// Damage the entity /// PARAMS: /// ent - entity to damage FUNC BOOL GGSM_ENTITY_DAMAGE(GGSM_ENTITY &ent, INT iDP = 1, BOOL bIgnoreInvunerable = FALSE) IF (GET_GAME_TIMER() < ent.iInvTimeMS) AND (bIgnoreInvunerable = FALSE) RETURN FALSE ENDIF IF (ent.eState != GGSM_ENTITY_STATE_ALIVE) RETURN FALSE ENDIF // check to see if damage affects parent (this is for bosses who have multiple bits) INT iArrayIndex = GGSM_ENTITY_GET_ARRAY_INDEX(ent) INT iGroupID = GGSM_ENTITY_GET_GROUP_ID(ent) IF (iGroupID != GGSM_INVALID_GROUP_ID) IF (sGGSMData.sEntityGroup[iGroupID].iLeader != GGSM_INVALID_ENTITY) IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_DAMAGE_HURTS_ROOT) GGSM_ENTITY_DAMAGE(sGGSMData.sEntities[sGGSMData.sEntityGroup[iGroupID].iLeader], iDP) RETURN FALSE ENDIF ENDIF ENDIF ent.iHP -= iDP IF (iArrayIndex = sGGSMData.iPlayerShipIndex) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_PLAYER_DAMAGED) ent.iInvTimeMS = GET_GAME_TIMER() + GGSM_PLAYER_INV_TIME SET_CONTROL_SHAKE(FRONTEND_CONTROL, 100, 100) sGGSMData.fChainMultiplier = 0 sGGSMData.iNoDamageBonus = 0 ENDIF IF (ent.eType = GGSM_ENTITY_PLAYERSHIELD) SET_CONTROL_SHAKE(FRONTEND_CONTROL, 100, 100) ENDIF IF (ent.iHP <= 0) ent.iHP = 0 IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_DIE_ONLY_FROM_EXPLOSIONS) GGSM_ENTITY_SET_STATE(ent, GGSM_ENTITY_STATE_FAKE_EXPLODING) RETURN TRUE ENDIF IF (ent.eType = GGSM_ENTITY_PLAYERSHIELD) GGSM_ENTITY_DESTROY(ent) ELSE GGSM_ENTITY_EXPLODE(ent) ENDIF RETURN TRUE ENDIF GGSM_ENTITY_DATA dat = GGSM_ENTITY_DATA_GET(ent.eType) GGSM_PLAY_SOUND_FROM_POSITION(dat.eDamageSound, ent.sWorld.vPosition) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_TOOK_DAMAGE_THIS_FRAME) IF (iArrayIndex = sGGSMData.iPlayerShipIndex) ent.iInvTimeMS = GET_GAME_TIMER() + GGSM_PLAYER_INV_TIME ELIF GGSM_ENTITY_IS_STRONG(ent) ent.iInvTimeMS = GET_GAME_TIMER() + GGSM_BOSS_INV_TIME ELSE ent.iInvTimeMS = GET_GAME_TIMER() + GGSM_ENTITY_INV_TIME ENDIF RETURN FALSE ENDFUNC /// PURPOSE: /// Update the projectile array /// PARAMS: /// array - array /// RETURNS: /// # of active projectiles FUNC INT GGSM_ENTITY_NUKE_ARRAY(GGSM_ENTITY &array[], BOOL bAllied) INT i, iDead INT cnt = COUNT_OF(array) INT dp REPEAT cnt i IF (array[i].eState = GGSM_ENTITY_STATE_ALIVE) IF (IS_BITMASK_ENUM_AS_ENUM_SET(array[i].eFlags, GGSM_ENTITY_BIT_IS_PLAYER_ALLIED) = bAllied) IF NOT GGSM_ENTITY_IS_STRONG(array[i]) IF GGSM_ENTITY_DAMAGE(array[i], 30, TRUE) iDead ++ ENDIF ELSE dp = GGSM_ENTITY_GET_PERCENTAGE_OF_HEALTH(array[i], 30) IF GGSM_ENTITY_DAMAGE(array[i], dp, TRUE) iDead ++ ENDIF ENDIF ENDIF ENDIF ENDREPEAT RETURN iDead ENDFUNC /// PURPOSE: /// Update the projectile array /// PARAMS: /// array - array /// RETURNS: /// # of active projectiles FUNC INT GGSM_ENTITY_DAMAGE_ARRAY(GGSM_ENTITY &array[], BOOL bAllied, INT iDP) INT i, iDead INT cnt = COUNT_OF(array) REPEAT cnt i IF (array[i].eState = GGSM_ENTITY_STATE_ALIVE) IF (IS_BITMASK_ENUM_AS_ENUM_SET(array[i].eFlags, GGSM_ENTITY_BIT_IS_PLAYER_ALLIED) = bAllied) IF GGSM_ENTITY_DAMAGE(array[i], iDP, TRUE) iDead ++ ENDIF ENDIF ENDIF ENDREPEAT RETURN iDead ENDFUNC /// PURPOSE: /// Update the projectile array /// PARAMS: /// array - array /// RETURNS: /// # of active projectiles PROC GGSM_ENTITY_EXPLODE_ARRAY(GGSM_ENTITY &array[], BOOL bAllied) INT i INT cnt = COUNT_OF(array) CPRINTLN(DEBUG_MINIGAME, "GGSM_ENTITY_EXPLODE_ARRAY") REPEAT cnt i IF (IS_BITMASK_ENUM_AS_ENUM_SET(array[i].eFlags, GGSM_ENTITY_BIT_IS_PLAYER_ALLIED) = bAllied) IF (array[i].eState != GGSM_ENTITY_STATE_NONE) CPRINTLN(DEBUG_MINIGAME, "GGSM_ENTITY_EXPLODE_ARRAY - TYPE:", GGSM_ENTITY_TYPE_TO_STRING(array[i].eType)) GGSM_ENTITY_EXPLODE(array[i]) GGSM_ENTITY_SET_STATE(array[i], GGSM_ENTITY_STATE_EXPLODING) ENDIF ENDIF ENDREPEAT ENDPROC PROC GGSM_ENTITY_UPDATE_MOVEMENT(GGSM_ENTITY &ent) SWITCH (ent.eMoveType) CASE GGSM_MOVEMENT_ARC_BASE_LEFT CASE GGSM_MOVEMENT_ARC_BASE_RIGHT CASE GGSM_MOVEMENT_ARC_TOP_LEFT CASE GGSM_MOVEMENT_ARC_TOP_RIGHT GGSM_ENTITY_MOVE_ARC(ent) BREAK CASE GGSM_MOVEMENT_ATTACK_KAMAZAKE GGSM_ENTITY_MOVE_ATTACK_KAMAKAZE(ent) BREAK CASE GGSM_MOVEMENT_BG_ATTACK GGSM_ENTITY_MOVE_BG_ATTACK(ent) BREAK CASE GGSM_MOVEMENT_DESTRUCT_ON_IMPACT GGSM_ENTITY_MOVE_DESTRUCT_ON_IMPACT(ent) BREAK CASE GGSM_MOVEMENT_FOLLOW_PATH GGSM_ENTITY_MOVE_FOLLOW_PATH(ent) BREAK CASE GGSM_MOVEMENT_FOLLOW_REL_PATH GGSM_ENTITY_MOVE_FOLLOW_REL_PATH(ent) BREAK CASE GGSM_MOVEMENT_FORWARD_THEN_BACK GGSM_ENTITY_MOVE_FORWARD_THEN_BACK(ent) BREAK CASE GGSM_MOVEMENT_HALF_ARC_BASE_LEFT CASE GGSM_MOVEMENT_HALF_ARC_BASE_RIGHT CASE GGSM_MOVEMENT_HALF_ARC_TOP_LEFT CASE GGSM_MOVEMENT_HALF_ARC_TOP_RIGHT GGSM_ENTITY_MOVE_HALF_ARC(ent) BREAK CASE GGSM_MOVEMENT_KAMAZAKE GGSM_ENTITY_MOVE_KAMAKAZE(ent) BREAK CASE GGSM_MOVEMENT_MOVE_TO_VECTOR GGSM_ENTITY_MOVE_TO_VECTOR(ent) BREAK CASE GGSM_MOVEMENT_ORBIT GGSM_ENTITY_MOVE_ORBIT(ent) BREAK CASE GGSM_MOVEMENT_PLAYER_CONTROLLED GGSM_ENTITY_MOVE_PLAYER_CONTROLLED(ent) BREAK CASE GGSM_MOVEMENT_RANDOM_WANDER GGSM_ENTITY_MOVE_RANDOM_WANDER(ent) BREAK CASE GGSM_MOVEMENT_ROTATE_TO_FACE_VECTOR GGSM_ENTITY_MOVE_ROTATE_FACE_TO_VECTOR(ent) BREAK CASE GGSM_MOVEMENT_SIN_WAVE GGSM_ENTITY_MOVE_SINWAVE(ent) BREAK CASE GGSM_MOVEMENT_SNAKE_SECTION GGSM_ENTITY_MOVE_SNAKESECTION(ent) BREAK CASE GGSM_MOVEMENT_STRAIGHT GGSM_ENTITY_MOVE_STRAIGHT(ent) BREAK CASE GGSM_MOVEMENT_TARGETTED_WANDER GGSM_ENTITY_MOVE_TARGETTED_WANDER(ent) BREAK CASE GGSM_MOVEMENT_TRACK_PLAYER_Y GGSM_ENTITY_MOVE_TRACK_PLAYER_Y(ent) BREAK CASE GGSM_MOVEMENT_MIDDLE_Y_RANGE GGSM_ENTITY_MOVE_MIDDLE_Y_RANGE(ent) BREAK /* DEFAULT CASSERTLN(DEBUG_MINIGAME, "FORGOT TO WRITE THE MOVEMENT FUNCTION - USING DEFAULT - MOVE TYPE:", GGSM_MOVEMENT_TYPE_TO_STRING(ent.eMoveType)) GGSM_ENTITY_MOVE_STRAIGHT(ent) BREAK */ ENDSWITCH IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_FORCE_SCROLLING_TO_STOP) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_BRING_CAMERA_TO_STOP) ENDIF ENDPROC FUNC BOOL GGSM_ENTITY_UPDATE_EXPLOSIONS(GGSM_ENTITY &ent) INT ind FLOAT fSize VECTOR_2D vPos GGSM_ENTITY_DATA dat = GGSM_ENTITY_DATA_GET(ent.eType) BOOL bIsAllied = IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_IS_PLAYER_ALLIED) FLOAT spd = 0 +@ (GGSM_ENTITY_GET_SPEED(ent) / 2.0) ent.sLocal.vPosition.x += dat.vExplodeVelocity.x * spd ent.sLocal.vPosition.y += dat.vExplodeVelocity.y * spd IF bIsAllied ent.fExplodeTimer -= GET_FRAME_TIME() ELSE ent.fExplodeTimer -= (GET_FRAME_TIME() * sGGSMData.fTimeScale) ENDIF IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_FORCE_SCROLLING_TO_STOP) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_BRING_CAMERA_TO_STOP) ENDIF IF (ent.fTimer >= dat.fTotalExplodeTime) IF GGSM_GET_FREE_FXSPRITE(sGGSMData.sFXSprite, ind, sGGSMData.iExplosionSearchIndex) GGSM_FXSPRITE_INIT_ANIMATED(sGGSMData.sFXSprite[ind], ent.sWorld.vPosition, GGSM_SPRITE_ANIM_EXPLOSION, 2.0) GGSM_FXSPRITE_SET_PHYSICAL_RADIUS(sGGSMData.sFXSprite[ind], GGSM_GET_DOMINANT_SPRITE_SIZE(dat.eSpriteType) * 1.5) IF (dat.eDieSound != ARCADE_GAMES_SOUND_END) GGSM_PLAY_SOUND_FROM_POSITION(dat.eDieSound, ent.sWorld.vPosition) ENDIF IF GGSM_ENTITY_IS_MAIN_BOSS_SECTION(ent) GGSM_NUKE_WHITE_INSTANT() ENDIF GGSM_ENTITY_DESTROY(ent) RETURN TRUE ENDIF ENDIF IF (ent.fExplodeTimer > 0.0) RETURN FALSE ENDIF IF GGSM_GET_FREE_FXSPRITE(sGGSMData.sFXSprite, ind, sGGSMData.iExplosionSearchIndex) fSize = GGSM_GET_DOMINANT_SPRITE_SIZE(dat.eSpriteType) * GET_RANDOM_FLOAT_IN_RANGE(0.5, 1.0) vPos = GGSM_GET_RANDOM_POINT_ON_ENTITY(ent) GGSM_FXSPRITE_INIT_ANIMATED(sGGSMData.sFXSprite[ind], vPos, GGSM_SPRITE_ANIM_EXPLOSION, 2.0) GGSM_FXSPRITE_SET_PHYSICAL_RADIUS(sGGSMData.sFXSprite[ind], fSize) ent.fExplodeTimer = dat.fExplodeDelay ENDIF RETURN FALSE ENDFUNC FUNC BOOL GGSM_ENTITY_UPDATE_FAKE_EXPLOSIONS(GGSM_ENTITY &ent) INT ind FLOAT fSize VECTOR_2D vPos GGSM_ENTITY_DATA dat = GGSM_ENTITY_DATA_GET(ent.eType) BOOL bIsAllied = IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_IS_PLAYER_ALLIED) IF bIsAllied ent.fExplodeTimer -= GET_FRAME_TIME() ELSE ent.fExplodeTimer -= (GET_FRAME_TIME() * sGGSMData.fTimeScale) ENDIF IF (ent.fTimer >= dat.fTotalExplodeTime) GGSM_ENTITY_SET_STATE(ent, GGSM_ENTITY_STATE_UNDEAD) RETURN TRUE ENDIF IF (ent.fExplodeTimer > 0.0) RETURN FALSE ENDIF IF GGSM_GET_FREE_FXSPRITE(sGGSMData.sFXSprite, ind, sGGSMData.iExplosionSearchIndex) fSize = GGSM_GET_DOMINANT_SPRITE_SIZE(dat.eSpriteType) * GET_RANDOM_FLOAT_IN_RANGE(0.5, 1.0) vPos = GGSM_GET_RANDOM_POINT_ON_ENTITY(ent) GGSM_FXSPRITE_INIT_ANIMATED(sGGSMData.sFXSprite[ind], vPos, GGSM_SPRITE_ANIM_EXPLOSION, 2.0) GGSM_FXSPRITE_SET_PHYSICAL_RADIUS(sGGSMData.sFXSprite[ind], fSize) ent.fExplodeTimer = dat.fExplodeDelay ENDIF RETURN FALSE ENDFUNC FUNC BOOL GGSM_ENTITY_UPDATE(GGSM_ENTITY &ent) INT iParent = GGSM_ENTITY_GET_PARENT_INDEX(ent) BOOL bIsAllied = IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_IS_PLAYER_ALLIED) GGSM_ENTITY_DATA dat = GGSM_ENTITY_DATA_GET(ent.eType) // update timer sGGSMData.iEntitiesActive ++ IF bIsAllied ent.fTimer += GET_FRAME_TIME() ent.fMoveTimer += GET_FRAME_TIME() ELSE ent.fTimer += (GET_FRAME_TIME() * sGGSMData.fTimeScale) ent.fMoveTimer += (GET_FRAME_TIME() * sGGSMData.fTimeScale) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_ENEMIES_ACTIVE) ENDIF CLEAR_BITMASK_ENUM_AS_ENUM(ent.eMoveFlags, GGSM_MOVE_BIT_TARGET_POINT_REACHED_THIS_FRAME) IF (ent.eState = GGSM_ENTITY_STATE_ALIVE) GGSM_ENTITY_UPDATE_MOVEMENT(ent) ELIF (ent.eState = GGSM_ENTITY_STATE_EXPLODING) IF GGSM_ENTITY_UPDATE_EXPLOSIONS(ent) GGSM_ENTITY_DESTROY(ent) RETURN FALSE ENDIF ELIF (ent.eState = GGSM_ENTITY_STATE_FAKE_EXPLODING) GGSM_ENTITY_UPDATE_FAKE_EXPLOSIONS(ent) ENDIF // update parenting IF (iParent != GGSM_INVALID_ENTITY) IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(ent.eMoveFlags, GGSM_MOVE_BIT_POSITION_OVERRIDE) GGSM_TRANSFORM_LOCAL_TO_WORLD(sGGSMData.sEntities[iParent].sWorld, ent.sLocal, ent.sWorld) ENDIF ELSE ent.sWorld = ent.sLocal ENDIF IF (ent.eType = GGSM_ENTITY_PLAYERSHIELD) AND GGSM_DOES_PLAYER_SHIP_EXIST() ent.sWorld = sGGSMData.sEntities[sGGSMData.iPlayerShipIndex].sWorld ENDIF GGSM_COLLIDER_TRANSFORM(ent.sCollider, ent.sWorld, dat.sCollisionData) IF GGSM_ENTITY_UPDATE_SCREEN_CHECKS(ent) GGSM_ENTITY_DESTROY(ent) RETURN FALSE ENDIF IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_TOOK_DAMAGE_THIS_FRAME) CLEAR_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_TOOK_DAMAGE_THIS_FRAME) ENDIF // only do the stuff below if we are actually alive IF (ent.eState != GGSM_ENTITY_STATE_ALIVE) RETURN TRUE ENDIF IF (ent.eSpriteAnim != GGSM_SPRITE_ANIM_NONE) GGSM_SPRITE_UPDATE_ANIMATION(ent.eSpriteAnim, ent.fAnimFrame, NOT bIsAllied) ENDIF GGSM_ENTITY_UPDATE_WEAPON(ent) IF IS_BITMASK_ENUM_AS_ENUM_SET(ent.eFlags, GGSM_ENTITY_BIT_SELF_DESTRUCT) GGSM_ENTITY_EXPLODE(ent) RETURN FALSE ENDIF RETURN TRUE ENDFUNC // PURPOSE: /// Initialize an entity based on data type /// PARAMS: /// ent - entity to intialize /// eType - entity type /// vLocalPos - Local Position (for most objects this will be the world position /// fLocalRot - Local Rotation /// iParentEntity - index into sGGSMData.sEnemyShips for linking boss parts to each other (ONLY USE ON ENEMIES) PROC GGSM_ENTITY_INIT(GGSM_ENTITY &ent, GGSM_ENTITY_TYPE eType, VECTOR_2D vLocalPos, FLOAT fLocalRot = 0.0, BOOL bIsFriendly = FALSE, INT iParentEntity = GGSM_INVALID_ENTITY, BOOL bCountTowardsTakedown = TRUE) GGSM_ENTITY_RESET(ent) GGSM_ENTITY_DATA entData = GGSM_ENTITY_DATA_GET(eType) ent.eType = eType GGSM_ENTITY_RESET_HEALTH(ent) ent.eWeaponState = GGSM_WEAPON_STATE_READY ent.iPackedColor = GGSM_PACK_RGBA_COLOUR_STRUCT(sGGSMData.rgbaSprite) GGSM_ENTITY_SET_Z_DEPTH(ent, 0) GGSM_ENTITY_SET_STATE(ent, GGSM_ENTITY_STATE_ALIVE) GGSM_ENTITY_SET_WEAPON(ent, GGSM_WEAPON_DEFAULT) GGSM_ENTITY_SET_MOVEMENT_TYPE(ent, GGSM_MOVEMENT_NONE) GGSM_ENTITY_SET_ANIM_FRAME(ent, entData.iDefaultAnimFrame) // set initial bits IF (bIsFriendly) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_IS_PLAYER_ALLIED) ent.iInvTimeMS = GET_GAME_TIMER() + GGSM_PLAYER_INITIAL_INV_TIME ELSE CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_PLAYER_BOSS_INVUNERABLE) ENDIF // movement ent.sLocal.vPosition = vLocalPos ent.sLocal.fRotation = fLocalRot ent.iPackedLocalOrigin = GGSM_PACK_VECTOR_2D_TO_INT(vLocalPos) ent.fSpeed = entData.fBaseSpeed // parenting ent.iGroupID = GGSM_INVALID_GROUP_ID GGSM_ENTITY_SET_PARENT_INDEX(ent, iParentEntity) IF (iParentEntity != GGSM_INVALID_ENTITY) GGSM_TRANSFORM_LOCAL_TO_WORLD(sGGSMData.sEntities[iParentEntity].sWorld, ent.sLocal, ent.sWorld) GGSM_ENTITY_ATTACH_TO_PARENT(ent, sGGSMData.sEntities[iParentEntity], TRUE) ELSE ent.sWorld = ent.sLocal ENDIF IF NOT bIsFriendly SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) IF (bCountTowardsTakedown = FALSE) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_NO_TAKEDOWN_BONUS) ELSE sGGSMData.iEnemiesCreated ++ ENDIF ENDIF IF (ent.iGroupID != GGSM_INVALID_GROUP_ID) IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntityGroup[ent.iGroupID].eFlags, GGSM_GROUP_BIT_END_WHEN_ALL_OFFSCREEN) SET_BITMASK_ENUM_AS_ENUM(ent.eFlags, GGSM_ENTITY_BIT_REMOVE_WHEN_OFFSCREEN) ENDIF ENDIF CDEBUG1LN(DEBUG_MINIGAME, "GGSM_ENTITY_INIT - IND:", GGSM_ENTITY_GET_ARRAY_INDEX(ent), " TYPE:", GGSM_ENTITY_TYPE_TO_STRING(eType), " LOCAL:[", ent.sLocal.vPosition.x, ", ", ent.sLocal.vPosition.y, "] ", " WORLD:[", ent.sWorld.vPosition.x, ", ", ent.sWorld.vPosition.y, "]") GGSM_COLLIDER_TRANSFORM(ent.sCollider, ent.sWorld, entData.sCollisionData) //GGSM_ENTITY_UPDATE(ent) ENDPROC PROC GGSM_ENTITY_CONFIGURE_FROM_FORMATION(GGSM_ENTITY &ent, GGSM_FORMATION_DATA &dat) GGSM_ENTITY_SET_MOVEMENT_TYPE(ent, GGSM_FORMATION_GET_MOVEMENT_TYPE(dat)) GGSM_ENTITY_SET_PATH_INDEX(ent, GGSM_FORMATION_GET_PATH_INDEX(dat)) IF (GGSM_FORMATION_GET_WEAPON_TYPE(dat) != GGSM_WEAPON_DEFAULT) GGSM_ENTITY_SET_WEAPON(ent, GGSM_FORMATION_GET_WEAPON_TYPE(dat)) ENDIF ENDPROC PROC GGSM_DETONATE_ENTITY_GROUP(GGSM_ENTITY_GROUP &group) INT i REPEAT COUNT_OF(sGGSMData.sEntities) i IF IS_BIT_SET(group.iMemberBitSet, i) GGSM_ENTITY_EXPLODE(sGGSMData.sEntities[i]) ENDIF ENDREPEAT GGSM_RESET_ENTITY_GROUP(group) ENDPROC PROC GGSM_DETONATE_ENTITIES_OF_TYPE(GGSM_ENTITY_TYPE eType) INT i REPEAT COUNT_OF(sGGSMData.sEntities) i IF (sGGSMData.sEntities[i].eType = eType) GGSM_ENTITY_EXPLODE(sGGSMData.sEntities[i]) ENDIF ENDREPEAT ENDPROC PROC GGSM_DESTROY_ENTITIES_OF_TYPE(GGSM_ENTITY_TYPE eType) INT i REPEAT COUNT_OF(sGGSMData.sEntities) i IF (sGGSMData.sEntities[i].eType = eType) GGSM_ENTITY_DESTROY(sGGSMData.sEntities[i]) ENDIF ENDREPEAT ENDPROC PROC GGSM_DESTROY_ENTITIES_OF_FACTION(BOOL bAllied) INT i REPEAT COUNT_OF(sGGSMData.sEntities) i IF (IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[i].eFlags, GGSM_ENTITY_BIT_IS_PLAYER_ALLIED) = bAllied) GGSM_ENTITY_DESTROY(sGGSMData.sEntities[i]) ENDIF ENDREPEAT ENDPROC //------------------------------------------------- // BOSS CONTROLLER FUNCTION //------------------------------------------------- FUNC BOOL GGSM_BOSS_BREAD_INIT(GGSM_BOSS_CONTROLLER &boss) INT iLeader, iGroupID, iChump // find free group iGroupID = GGSM_GET_FREE_ENTITY_GROUP(sGGSMData.sEntityGroup) IF (iGroupID = GGSM_INVALID_GROUP_ID) RETURN FALSE ENDIF // create smoothie IF (GGSM_COUNT_FREE_ENTITIES(sGGSMData.sEntities) < 5) RETURN FALSE ENDIF IF NOT GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iLeader, sGGSMData.iEntitySearchIndex) RETURN FALSE ENDIF // create granana GGSM_RESET_BOSS_CONTROLLER(boss, GGSM_BOSS_BREAD) boss.iGroupID = iGroupID SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntityGroup[iGroupID].eFlags, GGSM_GROUP_BIT_DIE_WHEN_LEADER_DIES) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntityGroup[iGroupID].eFlags, GGSM_GROUP_BIT_ALLOW_OFFSCREEN) GGSM_ENTITY_INIT(sGGSMData.sEntities[iLeader], GGSM_ENTITY_BOSS_BREAD_FACE, INIT_VECTOR_2D(2400, 540)) GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iLeader], GGSM_BOSS_SECTION_BREAD_FACE) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iLeader], iGroupID) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[iLeader], 5) GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iChump, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[iChump], GGSM_ENTITY_BOSS_BREAD_TOP_LEFT, INIT_VECTOR_2D(0, 0), DEFAULT, DEFAULT, iLeader) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iChump], iGroupID) GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iChump], GGSM_BOSS_SECTION_BREAD_TOP_LEFT, FALSE) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[iChump], 4) IF (sGGSMData.bHardMode) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iChump], GGSM_WEAPON_ENEMYSPREAD) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_WPN_SINGLE_SHOT_MODE) ENDIF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iChump, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[iChump], GGSM_ENTITY_BOSS_BREAD_BOTTOM_LEFT, INIT_VECTOR_2D(0, 0), DEFAULT, DEFAULT, iLeader) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iChump], iGroupID) GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iChump], GGSM_BOSS_SECTION_BREAD_BASE_LEFT, FALSE) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[iChump], 3) IF (sGGSMData.bHardMode) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iChump], GGSM_WEAPON_ENEMYSPREAD) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_WPN_SINGLE_SHOT_MODE) ENDIF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iChump, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[iChump], GGSM_ENTITY_BOSS_BREAD_TOP_RIGHT, INIT_VECTOR_2D(0, 0), DEFAULT, DEFAULT, iLeader) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iChump], iGroupID) GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iChump], GGSM_BOSS_SECTION_BREAD_TOP_RIGHT, FALSE) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[iChump], 2) IF (sGGSMData.bHardMode) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iChump], GGSM_WEAPON_ENEMYSPREAD) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_WPN_SINGLE_SHOT_MODE) ENDIF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iChump, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[iChump], GGSM_ENTITY_BOSS_BREAD_BOTTOM_RIGHT, INIT_VECTOR_2D(0, 0), DEFAULT, DEFAULT, iLeader) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iChump], iGroupID) GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iChump], GGSM_BOSS_SECTION_BREAD_BASE_RIGHT, FALSE) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[iChump], 1) IF (sGGSMData.bHardMode) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iChump], GGSM_WEAPON_ENEMYSPREAD) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_WPN_SINGLE_SHOT_MODE) ENDIF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iChump, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[iChump], GGSM_ENTITY_BOSS_BREAD_EYEBROWS, INIT_VECTOR_2D(-40, -80), DEFAULT, DEFAULT, iLeader) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iChump], iGroupID) GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iChump], GGSM_BOSS_SECTION_BREAD_BROWS, FALSE) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[iChump], 0) GGSM_ENTITY_SET_ANIMATION(sGGSMData.sEntities[iChump], GGSM_SPRITE_ANIM_BREAD_EYEBROWS) GGSM_TRIGGER_MUSIC_EVENT("ARCADE_SM_BOSS_START") RETURN TRUE ENDFUNC FUNC BOOL GGSM_BOSS_DR_DANK_INIT(GGSM_BOSS_CONTROLLER &boss) INT iLeader, iChump INT iGroupID // find free group iGroupID = GGSM_GET_FREE_ENTITY_GROUP(sGGSMData.sEntityGroup) IF (iGroupID = GGSM_INVALID_GROUP_ID) RETURN FALSE ENDIF // create smoothie IF NOT GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iLeader, sGGSMData.iEntitySearchIndex) RETURN FALSE ENDIF // create granana GGSM_RESET_BOSS_CONTROLLER(boss, GGSM_BOSS_DR_DANK) boss.iGroupID = iGroupID SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntityGroup[iGroupID].eFlags, GGSM_GROUP_BIT_DIE_WHEN_LEADER_DIES) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntityGroup[iGroupID].eFlags, GGSM_GROUP_BIT_ALLOW_OFFSCREEN) GGSM_RESET_BOSS_CONTROLLER(boss, GGSM_BOSS_DR_DANK) GGSM_ENTITY_INIT(sGGSMData.sEntities[iLeader], GGSM_ENTITY_BOSS_DR_DANK_TOP, INIT_VECTOR_2D(2400, 540)) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_DANK_SCATTER) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ALT_SPREAD) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[iLeader], 2) sGGSMData.sEntities[iLeader].iNumShotsOverride = 5 GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iLeader], GGSM_BOSS_SECTION_DR_DANK_TOP) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iLeader], iGroupID) // create wig GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iChump, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[iChump], GGSM_ENTITY_BOSS_DR_DANK_MIDDLE, INIT_VECTOR_2D(0, 240), DEFAULT, DEFAULT, iLeader) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iChump], iGroupID) GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iChump], GGSM_BOSS_SECTION_DR_DANK_MIDDLE, FALSE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_DIE_ONLY_FROM_EXPLOSIONS) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[iChump], 1) // create glasses GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iChump, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[iChump], GGSM_ENTITY_BOSS_DR_DANK_BOTTOM, INIT_VECTOR_2D(0, 290), DEFAULT, DEFAULT, iLeader) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iChump], iGroupID) GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iChump], GGSM_BOSS_SECTION_DR_DANK_BOTTOM, FALSE) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_DIE_ONLY_FROM_EXPLOSIONS) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[iChump], 0) // create rockets launchers IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iChump, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[iChump], GGSM_ENTITY_BOSS_DR_DANK_RLAUNCHER, INIT_VECTOR_2D(-137, -22), DEFAULT, DEFAULT, iLeader) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iChump], iGroupID) GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iChump], GGSM_BOSS_SECTION_DR_DANK_ROCKET_L1, FALSE) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_DAMAGE_HURTS_ROOT) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[iChump], 0) ENDIF IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iChump, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[iChump], GGSM_ENTITY_BOSS_DR_DANK_RLAUNCHER, INIT_VECTOR_2D(94, -21), DEFAULT, DEFAULT, iLeader) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iChump], iGroupID) GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iChump], GGSM_BOSS_SECTION_DR_DANK_ROCKET_R1, FALSE) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_DAMAGE_HURTS_ROOT) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[iChump], 0) ENDIF IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iChump, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[iChump], GGSM_ENTITY_BOSS_DR_DANK_RHLAUNCHER, INIT_VECTOR_2D(-93, 17), DEFAULT, DEFAULT, iLeader) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iChump], iGroupID) GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iChump], GGSM_BOSS_SECTION_DR_DANK_ROCKET_L2, FALSE) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_DAMAGE_HURTS_ROOT) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_WPN_SINGLE_SHOT_MODE) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[iChump], 0) ENDIF IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iChump, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[iChump], GGSM_ENTITY_BOSS_DR_DANK_RHLAUNCHER, INIT_VECTOR_2D(34, 28), DEFAULT, DEFAULT, iLeader) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iChump], iGroupID) GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iChump], GGSM_BOSS_SECTION_DR_DANK_ROCKET_R2, FALSE) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_DAMAGE_HURTS_ROOT) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_WPN_SINGLE_SHOT_MODE) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[iChump], 0) ENDIF GGSM_TRIGGER_MUSIC_EVENT("ARCADE_SM_FINAL_BOSS_START") RETURN TRUE ENDFUNC FUNC BOOL GGSM_BOSS_GRANANA_INIT(GGSM_BOSS_CONTROLLER &boss) INT iLeader, iChump INT iGroupID // find free group iGroupID = GGSM_GET_FREE_ENTITY_GROUP(sGGSMData.sEntityGroup) IF (iGroupID = GGSM_INVALID_GROUP_ID) RETURN FALSE ENDIF // create smoothie IF (GGSM_COUNT_FREE_ENTITIES(sGGSMData.sEntities) < 3) RETURN FALSE ENDIF IF NOT GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iLeader, sGGSMData.iEntitySearchIndex) RETURN FALSE ENDIF // create granana GGSM_RESET_BOSS_CONTROLLER(boss, GGSM_BOSS_GRANANA) boss.iGroupID = iGroupID SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntityGroup[iGroupID].eFlags, GGSM_GROUP_BIT_DIE_WHEN_LEADER_DIES) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntityGroup[iGroupID].eFlags, GGSM_GROUP_BIT_ALLOW_OFFSCREEN) GGSM_ENTITY_INIT(sGGSMData.sEntities[iLeader], GGSM_ENTITY_BOSS_GRANANA, INIT_VECTOR_2D(2400, 540)) GGSM_ENTITY_SET_ANIMATION(sGGSMData.sEntities[iLeader], GGSM_SPRITE_ANIM_GRANANA) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_GRANANASPREAD1) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ALT_SPREAD) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[iLeader], 2) sGGSMData.sEntities[iLeader].iNumShotsOverride = 2 GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iLeader], GGSM_BOSS_SECTION_GRANANA) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iLeader], iGroupID) // create wig GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iChump, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[iChump], GGSM_ENTITY_BOSS_GRANANA_HAIR, INIT_VECTOR_2D(-80, -160), 0, DEFAULT, iLeader) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iChump], iGroupID) GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iChump], GGSM_BOSS_SECTION_GRANANA_HAIR) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_DAMAGE_HURTS_ROOT) // create glasses GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iChump, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[iChump], GGSM_ENTITY_BOSS_GRANANA_GLASSES, INIT_VECTOR_2D(-20, -60), 0, DEFAULT, iLeader) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iChump], iGroupID) GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iChump], GGSM_BOSS_SECTION_GRANANA_GLASSES) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_DAMAGE_HURTS_ROOT) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iChump], GGSM_WEAPON_ENEMYLASER) GGSM_TRIGGER_MUSIC_EVENT("ARCADE_SM_BOSS_START") RETURN TRUE ENDFUNC FUNC BOOL GGSM_BOSS_MARINE_INIT(GGSM_BOSS_CONTROLLER &boss) INT iLeader, iGroupID INT iChump // find free group iGroupID = GGSM_GET_FREE_ENTITY_GROUP(sGGSMData.sEntityGroup) IF (iGroupID = GGSM_INVALID_GROUP_ID) RETURN FALSE ENDIF // create smoothie IF NOT GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iLeader, sGGSMData.iEntitySearchIndex) RETURN FALSE ENDIF // create granana GGSM_RESET_BOSS_CONTROLLER(boss, GGSM_BOSS_MARINE) boss.iGroupID = iGroupID SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntityGroup[iGroupID].eFlags, GGSM_GROUP_BIT_DIE_WHEN_LEADER_DIES) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntityGroup[iGroupID].eFlags, GGSM_GROUP_BIT_ALLOW_OFFSCREEN) GGSM_ENTITY_INIT(sGGSMData.sEntities[iLeader], GGSM_ENTITY_BOSS_MARINE, INIT_VECTOR_2D(2400, 540)) GGSM_ENTITY_SET_ANIMATION(sGGSMData.sEntities[iLeader], GGSM_SPRITE_ANIM_MARINE) GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iLeader], GGSM_BOSS_SECTION_MARINE) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iLeader], iGroupID) IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iChump, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[iChump], GGSM_ENTITY_BOSS_MARINE_LAUNCHER, INIT_VECTOR_2D(-176, 56), 0, DEFAULT, iLeader) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iChump], iGroupID) GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iChump], GGSM_BOSS_SECTION_MARINE_LAUNCHER, FALSE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_DAMAGE_HURTS_ROOT) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iChump], GGSM_WEAPON_NONE) ENDIF GGSM_TRIGGER_MUSIC_EVENT("ARCADE_SM_BOSS_START") RETURN TRUE ENDFUNC PROC GGSM_BOSS_SMOOTHIE_CREATE_ORBITERS(GGSM_BOSS_CONTROLLER &boss, INT iNumber = 5) INT n, iChump INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_SMOOTHIE) IF (iLeader = GGSM_INVALID_ENTITY) EXIT ENDIF IF (sGGSMData.bHardMode) iNumber += 3 ENDIF FLOAT fAngleDiff = 360.0 / TO_FLOAT(iNumber) FLOAT fAngle = GET_RANDOM_FLOAT_IN_RANGE(0, 360) REPEAT iNumber n IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iChump, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[iChump], GGSM_ENTITY_CIRCLE_SHIP_YELLOW, INIT_VECTOR_2D(0, 0), 0, FALSE, iLeader, FALSE) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[iChump], GGSM_MOVEMENT_ORBIT, 300.0, fAngle + (n * fAngleDiff), 0.5) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iChump], GGSM_WEAPON_ENEMYSHOT) sGGSMData.sEntities[iChump].iHP = 3 CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iChump].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) ENDIF ENDREPEAT ENDPROC FUNC BOOL GGSM_BOSS_SMOOTHIE_INIT(GGSM_BOSS_CONTROLLER &boss) INT iLeader, iGroupID // find free group iGroupID = GGSM_GET_FREE_ENTITY_GROUP(sGGSMData.sEntityGroup) IF (iGroupID = GGSM_INVALID_GROUP_ID) RETURN FALSE ENDIF // create smoothie IF NOT GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iLeader, sGGSMData.iEntitySearchIndex) RETURN FALSE ENDIF GGSM_RESET_BOSS_CONTROLLER(boss, GGSM_BOSS_SMOOTHIE) boss.iGroupID = iGroupID SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGroupID].eFlags, GGSM_GROUP_BIT_DIE_WHEN_LEADER_DIES) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGroupID].eFlags, GGSM_GROUP_BIT_ALLOW_OFFSCREEN) GGSM_ENTITY_INIT(sGGSMData.sEntities[iLeader], GGSM_ENTITY_BOSS_SMOOTHIE, INIT_VECTOR_2D(2400, 540)) GGSM_ENTITY_SET_ANIMATION(sGGSMData.sEntities[iLeader], GGSM_SPRITE_ANIM_SMOOTHIE) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iLeader], iGroupID) GGSM_ADD_ENTITY_TO_BOSS_CONTROLLER(boss, sGGSMData.sEntities[iLeader], GGSM_BOSS_SECTION_SMOOTHIE) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_SMOOTHIESPREAD) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[iLeader], 2) GGSM_BOSS_SMOOTHIE_CREATE_ORBITERS(boss) GGSM_TRIGGER_MUSIC_EVENT("ARCADE_SM_BOSS_START") RETURN TRUE ENDFUNC FUNC BOOL GGSM_BOSS_INIT(GGSM_BOSS_CONTROLLER &boss) SWITCH (boss.eType) CASE GGSM_BOSS_BREAD RETURN GGSM_BOSS_BREAD_INIT(boss) CASE GGSM_BOSS_DR_DANK RETURN GGSM_BOSS_DR_DANK_INIT(boss) CASE GGSM_BOSS_GRANANA RETURN GGSM_BOSS_GRANANA_INIT(boss) CASE GGSM_BOSS_MARINE RETURN GGSM_BOSS_MARINE_INIT(boss) CASE GGSM_BOSS_SMOOTHIE RETURN GGSM_BOSS_SMOOTHIE_INIT(boss) ENDSWITCH RETURN FALSE ENDFUNC //------------------------------------------------- // BOSS CONTROLLER SMOOTHIE FUNCTION //------------------------------------------------- PROC GGSM_BOSS_CONTROLLER_UPDATE_SMOOTHIE_PATTERN_A(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_SMOOTHIE) IF (iLeader = GGSM_INVALID_ENTITY) AND (boss.eState >= GGSM_BOSS_STATE_ARRIVE) EXIT ENDIF SWITCH (boss.iBossPatternState) CASE 0 IF (boss.fStateTimer >= 0.5) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_RANDOM_SPREAD) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_SMOOTHIESPREAD) boss.iInternalCounter = GET_RANDOM_INT_IN_RANGE(2, 4) boss.iBossPatternState ++ ENDIF BREAK CASE 1 IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_BURST_RELOAD_THIS_FRAME) boss.iInternalCounter -- ENDIF IF (boss.iInternalCounter <= 0) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_SMOOTHIE_PATTERN_B(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_SMOOTHIE) IF (iLeader = GGSM_INVALID_ENTITY) AND (boss.eState >= GGSM_BOSS_STATE_ARRIVE) EXIT ENDIF SWITCH (boss.iBossPatternState) CASE 0 CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) IF (boss.fStateTimer >= 1.25) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_RANDOM_SPREAD) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_SMOOTHIEVULCAN) boss.iInternalCounter = 0 boss.iBossPatternState ++ ENDIF BREAK CASE 1 IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_BURST_RELOAD_THIS_FRAME) boss.iInternalCounter ++ ENDIF IF (boss.iInternalCounter >= 3) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_SMOOTHIE_PATTERN_C(GGSM_BOSS_CONTROLLER &boss) FLOAT f INT iChump VECTOR_2D v FLOAT t INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_SMOOTHIE) IF (iLeader = GGSM_INVALID_ENTITY) AND (boss.eState >= GGSM_BOSS_STATE_ARRIVE) EXIT ENDIF SWITCH (boss.iBossPatternState) CASE 0 GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iLeader], INIT_VECTOR_2D(2000, 540)) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) IF (boss.iSubGroupID != GGSM_INVALID_GROUP_ID) GGSM_DETONATE_ENTITY_GROUP(sGGSMData.sEntityGroup[boss.iSubGroupID]) ENDIF boss.iBossPatternState ++ BREAK CASE 1 IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLeader].eMoveFlags, GGSM_MOVE_BIT_COMPLETE) EXIT ENDIF GGSM_DESTROY_ENTITIES_OF_TYPE(GGSM_ENTITY_CIRCLE_SHIP_YELLOW) boss.iSubGroupID = GGSM_GET_FREE_ENTITY_GROUP(sGGSMData.sEntityGroup) IF (boss.iSubGroupID != GGSM_INVALID_GROUP_ID) GGSM_RESET_ENTITY_GROUP(sGGSMData.sEntityGroup[boss.iSubGroupID]) IF (GGSM_BOSS_CONTROLLER_GET_HP_PERCENTAGE(boss) < 0.5) boss.iInternalCounter = GET_RANDOM_INT_IN_RANGE(6, 10) ELSE boss.iInternalCounter = GET_RANDOM_INT_IN_RANGE(3, 5) ENDIF IF (sGGSMData.bHardMode) boss.iInternalCounter += 3 ENDIF boss.fStateTimer = 0.0 ENDIF boss.iBossPatternState ++ BREAK CASE 2 t = 0.25 IF (GGSM_BOSS_CONTROLLER_GET_HP_PERCENTAGE(boss) < 0.5) t = 0.125 ENDIF IF (boss.fStateTimer >= t) IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iChump, sGGSMData.iEntitySearchIndex) f = GET_RANDOM_FLOAT_IN_RANGE(800.0, 900.0) v = GGSM_GET_VECTOR_FROM_HEADING(GET_RANDOM_FLOAT_IN_RANGE(0, 360)) v.x *= f v.y *= f v.x += cfBASE_SCREEN_HALF_WIDTH v.y += cfBASE_SCREEN_HALF_HEIGHT GGSM_ENTITY_INIT(sGGSMData.sEntities[iChump], GGSM_ENTITY_CHERRYBOMB, v, 0, FALSE, DEFAULT, FALSE) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[iChump], GGSM_MOVEMENT_DESTRUCT_ON_IMPACT) GGSM_ENTITY_SET_TARGET_WORLD_VECTOR(sGGSMData.sEntities[iChump], GGSM_GET_TARGET_AT_PLAYER_POSITION()) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iChump], GGSM_WEAPON_NONE) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iChump], boss.iSubGroupID) boss.iInternalCounter -- boss.fStateTimer = 0.0 ENDIF ENDIF IF (boss.iInternalCounter <= 0) boss.iBossPatternState ++ ENDIF BREAK CASE 3 IF (boss.iSubGroupID != GGSM_INVALID_GROUP_ID) AND GGSM_ENTITY_GROUP_HAS_GROUP_FINISHED(sGGSMData.sEntityGroup[boss.iSubGroupID]) GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iLeader], INIT_VECTOR_2D(1450, 540)) iChump = 5 IF (GGSM_BOSS_CONTROLLER_GET_HP_PERCENTAGE(boss) < 0.5) GGSM_BOSS_SMOOTHIE_CREATE_ORBITERS(boss, iChump + 2) ELSE GGSM_BOSS_SMOOTHIE_CREATE_ORBITERS(boss, iChump) ENDIF boss.iBossPatternState ++ ENDIF BREAK CASE 4 IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLeader].eMoveFlags, GGSM_MOVE_BIT_COMPLETE) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_SMOOTHIE_SELECT_ATTACK_PATTERN(GGSM_BOSS_CONTROLLER &boss) INT i = GET_RANDOM_INT_IN_RANGE(0, 3) SWITCH (i) CASE 0 GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_PATTERN_B) BREAK CASE 1 GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_PATTERN_C) BREAK DEFAULT GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_PATTERN_A) BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_SMOOTHIE(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_SMOOTHIE) IF (iLeader = GGSM_INVALID_ENTITY) AND (boss.eState >= GGSM_BOSS_STATE_ARRIVE) EXIT ENDIF SWITCH (boss.eState) CASE GGSM_BOSS_STATE_ARRIVE IF (boss.bStateInit = FALSE) GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iLeader], INIT_VECTOR_2D(1350, 540)) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) boss.bStateInit = TRUE ELIF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLeader].eMoveFlags, GGSM_MOVE_BIT_COMPLETE) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[iLeader], GGSM_MOVEMENT_NONE) GGSM_DIALOG_CONTROLLER_START_DIALOG(sGGSMData.sDialogController, GGSM_DIALOG_BOSS_SMOOTHIE_START) GGSM_BOSS_CONTROLLER_SET_ATTACK_PATTERN(boss, GGSM_BOSS_STATE_PATTERN_A) ENDIF BREAK CASE GGSM_BOSS_STATE_ACTIVE IF GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[iLeader]) GGSM_BOSS_CONTROLLER_SELECT_ATTACK_PATTERN(boss) ENDIF BREAK CASE GGSM_BOSS_STATE_PATTERN_A GGSM_BOSS_CONTROLLER_UPDATE_SMOOTHIE_PATTERN_A(boss) BREAK CASE GGSM_BOSS_STATE_PATTERN_B GGSM_BOSS_CONTROLLER_UPDATE_SMOOTHIE_PATTERN_B(boss) BREAK CASE GGSM_BOSS_STATE_PATTERN_C GGSM_BOSS_CONTROLLER_UPDATE_SMOOTHIE_PATTERN_C(boss) BREAK CASE GGSM_BOSS_STATE_PATTERN_D CASE GGSM_BOSS_STATE_PATTERN_E GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) BREAK CASE GGSM_BOSS_STATE_PLAYER_DEAD IF (boss.bStateInit = FALSE) GGSM_DIALOG_CONTROLLER_START_DIALOG(sGGSMData.sDialogController, GGSM_DIALOG_BOSS_SMOOTHIE_FAILED) boss.bStateInit = TRUE ENDIF BREAK CASE GGSM_BOSS_STATE_DEAD IF (boss.bStateInit = FALSE) GGSM_DIALOG_CONTROLLER_START_DIALOG(sGGSMData.sDialogController, GGSM_DIALOG_BOSS_SMOOTHIE_DEFEATED) boss.bStateInit = TRUE ELIF NOT GGSM_IS_DIALOG_ACTIVE() GGSM_ENTITY_EXPLODE_ARRAY(sGGSMData.sEntities, FALSE) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_DONE) ENDIF BREAK ENDSWITCH ENDPROC //------------------------------------------------- // BOSS CONTROLLER BREAD FUNCTION //------------------------------------------------- FUNC INT GGSM_BOSS_CONTROLLER_COUNT_BREAD_SLICES(GGSM_BOSS_CONTROLLER &boss) INT cnt = 0 INT i, ind REPEAT 4 i ind = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, 1 + i) IF (ind != GGSM_INVALID_ENTITY) AND (sGGSMData.sEntities[ind].eState = GGSM_ENTITY_STATE_ALIVE) cnt ++ ENDIF ENDREPEAT RETURN cnt ENDFUNC FUNC BOOL GGSM_BOSS_CONTROLLER_HAVE_BREAD_SLICES_STOPPED_MOVING(GGSM_BOSS_CONTROLLER &boss) INT i, ind REPEAT 4 i ind = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, 1 + i) IF (ind != GGSM_INVALID_ENTITY) AND (sGGSMData.sEntities[ind].eState = GGSM_ENTITY_STATE_ALIVE) IF NOT GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[ind]) RETURN FALSE ENDIF ENDIF ENDREPEAT RETURN TRUE ENDFUNC PROC GGSM_BOSS_CONTROLLER_EXPLODE_BREAD(GGSM_BOSS_CONTROLLER &boss, FLOAT spdScalar = 1.0) INT i, ind INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_BREAD_FACE) BOOL bPlaySound = FALSE VECTOR_2D vPos, vDir REPEAT 4 i ind = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_BREAD_BASE_LEFT + i) IF (ind != GGSM_INVALID_ENTITY) AND (sGGSMData.sEntities[ind].eState = GGSM_ENTITY_STATE_ALIVE) GGSM_ENTITY_DETACH_FROM_PARENT(sGGSMData.sEntities[ind]) vDir = GGSM_GET_VECTOR_FROM_HEADING(45.0 + (i * 90.0)) vPos = sGGSMData.sEntities[iLeader].sWorld.vPosition vPos.x += (vDir.x * 800.0) vPos.y += (vDir.y * 800.0) GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[ind], vPos) GGSM_ENTITY_SCALE_BASE_SPEED(sGGSMData.sEntities[ind], spdScalar) bPlaySound = TRUE ENDIF ENDREPEAT IF (bPlaySound) GGSM_PLAY_SOUND_FROM_POSITION(ARCADE_GAMES_SOUND_GGSM_BOSS_BREAD_SPLIT, sGGSMData.sEntities[iLeader].sWorld.vPosition) ENDIF ENDPROC PROC GGSM_BOSS_CONTROLLER_DISPERSE_BREAD(GGSM_BOSS_CONTROLLER &boss, VECTOR_2D vPos, FLOAT fDelay = 0.0, FLOAT spdScalar = 1.0) INT i, ind INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_BREAD_FACE) BOOL bPlaySound = FALSE REPEAT 4 i ind = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, 1 + i) IF (ind != GGSM_INVALID_ENTITY) AND (sGGSMData.sEntities[ind].eState = GGSM_ENTITY_STATE_ALIVE) GGSM_ENTITY_DETACH_FROM_PARENT(sGGSMData.sEntities[ind]) GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[ind], vPos, fDelay * i) GGSM_ENTITY_SCALE_BASE_SPEED(sGGSMData.sEntities[ind], spdScalar) bPlaySound = TRUE ENDIF ENDREPEAT IF (bPlaySound) GGSM_PLAY_SOUND_FROM_POSITION(ARCADE_GAMES_SOUND_GGSM_BOSS_BREAD_SPLIT, sGGSMData.sEntities[iLeader].sWorld.vPosition) ENDIF ENDPROC PROC GGSM_BOSS_CONTROLLER_REASSEMBLE_BREAD(GGSM_BOSS_CONTROLLER &boss) INT i, ind INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_BREAD_FACE) BOOL bPlaySound = FALSE REPEAT 4 i ind = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_BREAD_BASE_LEFT + i) IF (ind != GGSM_INVALID_ENTITY) AND (sGGSMData.sEntities[ind].eState = GGSM_ENTITY_STATE_ALIVE) GGSM_ENTITY_ATTACH_TO_PARENT(sGGSMData.sEntities[ind], sGGSMData.sEntities[iLeader]) GGSM_ENTITY_RETURN_TO_ORIGIN(sGGSMData.sEntities[ind]) GGSM_ENTITY_RESET_BASE_SPEED(sGGSMData.sEntities[ind]) bPlaySound = TRUE ENDIF ENDREPEAT IF (bPlaySound) GGSM_PLAY_SOUND_FROM_POSITION(ARCADE_GAMES_SOUND_GGSM_BOSS_BREAD_ASSEMBLE, sGGSMData.sEntities[iLeader].sWorld.vPosition) ENDIF ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_BREAD_PATTERN_A(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_BREAD_FACE) INT iMouthCover = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_BREAD_BASE_LEFT) IF (iLeader = GGSM_INVALID_ENTITY) AND (boss.eState >= GGSM_BOSS_STATE_ARRIVE) EXIT ENDIF SWITCH (boss.iBossPatternState) CASE 0 IF (boss.fStateTimer > 1.0) GGSM_ENTITY_RESET_BASE_SPEED(sGGSMData.sEntities[iLeader]) IF (iMouthCover != GGSM_INVALID_ENTITY) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ELSE SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ENDIF GGSM_BOSS_CONTROLLER_EXPLODE_BREAD(boss) boss.iInternalCounter = 0 boss.iBossPatternState ++ ENDIF BREAK CASE 1 IF GGSM_BOSS_CONTROLLER_HAVE_BREAD_SLICES_STOPPED_MOVING(boss) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_BREADSPREAD) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) GGSM_BOSS_CONTROLLER_DISPERSE_BREAD(boss, GGSM_GET_TARGET_AT_PLAYER_POSITION()) boss.iBossPatternState ++ ENDIF BREAK CASE 2 IF GGSM_BOSS_CONTROLLER_HAVE_BREAD_SLICES_STOPPED_MOVING(boss) boss.iBossPatternState ++ boss.fStateTimer = 0.0 ENDIF BREAK CASE 3 IF (boss.fStateTimer > 3.0) GGSM_BOSS_CONTROLLER_EXPLODE_BREAD(boss) boss.iBossPatternState ++ ENDIF BREAK CASE 4 IF GGSM_BOSS_CONTROLLER_HAVE_BREAD_SLICES_STOPPED_MOVING(boss) GGSM_BOSS_CONTROLLER_REASSEMBLE_BREAD(boss) boss.iBossPatternState ++ ENDIF BREAK CASE 5 IF GGSM_BOSS_CONTROLLER_HAVE_BREAD_SLICES_STOPPED_MOVING(boss) IF (iMouthCover != GGSM_INVALID_ENTITY) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ELSE SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ENDIF GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_BREAD_PATTERN_B(GGSM_BOSS_CONTROLLER &boss) VECTOR_2D vTarget INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_BREAD_FACE) INT iMouthCover = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_BREAD_BASE_LEFT) IF (iLeader = GGSM_INVALID_ENTITY) AND (boss.eState >= GGSM_BOSS_STATE_ARRIVE) EXIT ENDIF SWITCH (boss.iBossPatternState) CASE 0 IF (boss.fStateTimer > 0.5) vTarget = INIT_VECTOR_2D(540, 540) IF (iMouthCover != GGSM_INVALID_ENTITY) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ELSE SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ENDIF IF (sGGSMData.sEntities[iLeader].sWorld.vPosition.x < cfBASE_SCREEN_HALF_WIDTH) vTarget = INIT_VECTOR_2D(1400, 540) ENDIF GGSM_BOSS_CONTROLLER_DISPERSE_BREAD(boss, vTarget, 0.5, 2.0) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_BREADSPREAD) GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iLeader], vTarget, 3.0) GGSM_ENTITY_SCALE_BASE_SPEED(sGGSMData.sEntities[iLeader], 2.0) boss.iInternalCounter = 0 boss.iBossPatternState ++ ENDIF BREAK CASE 1 IF GGSM_BOSS_CONTROLLER_HAVE_BREAD_SLICES_STOPPED_MOVING(boss) IF GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[iLeader]) boss.iBossPatternState ++ boss.fStateTimer = 0.0 ENDIF ENDIF BREAK CASE 2 IF (boss.fStateTimer > 2.0) IF (iMouthCover != GGSM_INVALID_ENTITY) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ELSE SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ENDIF GGSM_BOSS_CONTROLLER_DISPERSE_BREAD(boss, INIT_VECTOR_2D(1400, 540), 0.5, 2.0) GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iLeader], INIT_VECTOR_2D(1400, 540), 3.0) GGSM_ENTITY_SCALE_BASE_SPEED(sGGSMData.sEntities[iLeader], 2.0) boss.iBossPatternState ++ ENDIF BREAK CASE 3 IF GGSM_BOSS_CONTROLLER_HAVE_BREAD_SLICES_STOPPED_MOVING(boss) IF GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[iLeader]) GGSM_BOSS_CONTROLLER_REASSEMBLE_BREAD(boss) boss.iBossPatternState ++ ENDIF ENDIF BREAK CASE 4 IF GGSM_BOSS_CONTROLLER_HAVE_BREAD_SLICES_STOPPED_MOVING(boss) IF (iMouthCover != GGSM_INVALID_ENTITY) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ELSE SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ENDIF GGSM_ENTITY_RESET_BASE_SPEED(sGGSMData.sEntities[iLeader]) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_BREAD_PATTERN_C(GGSM_BOSS_CONTROLLER &boss) INT iChump INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_BREAD_FACE) INT iMouthCover = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_BREAD_BASE_LEFT) IF (iLeader = GGSM_INVALID_ENTITY) AND (boss.eState >= GGSM_BOSS_STATE_ARRIVE) EXIT ENDIF SWITCH (boss.iBossPatternState) CASE 0 IF (boss.fStateTimer > 0.25) IF (iMouthCover != GGSM_INVALID_ENTITY) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ELSE SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ENDIF GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iLeader], INIT_VECTOR_2D(1010.0, 300.0)) boss.iInternalCounter = 0 boss.iBossPatternState ++ ENDIF BREAK CASE 1 IF GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[iLeader]) boss.iBossPatternState ++ boss.iInternalCounter = GET_RANDOM_INT_IN_RANGE(7, 11) boss.fStateTimer = 0.0 ENDIF BREAK CASE 2 IF (boss.fStateTimer > 0.25) IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iChump, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[iChump], GGSM_ENTITY_CRUMB_METEOR, INIT_VECTOR_2D(GET_RANDOM_FLOAT_IN_RANGE(400.0, 1500.0), 0.0), 0, FALSE, DEFAULT, FALSE) sGGSMData.sEntities[iChump].vLocalDirection = INIT_VECTOR_2D(0, 1) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[iChump], GGSM_MOVEMENT_STRAIGHT) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iChump], GGSM_WEAPON_NONE) GGSM_ENTITY_SCALE_BASE_SPEED(sGGSMData.sEntities[iChump], GET_RANDOM_FLOAT_IN_RANGE(0.75, 1.25)) boss.iInternalCounter -- boss.fStateTimer = 0.0 ENDIF ENDIF IF (boss.iInternalCounter <= 0) boss.iBossPatternState ++ boss.fStateTimer = 0.0 ENDIF BREAK CASE 3 IF (boss.fStateTimer > 1.0) GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iLeader], INIT_VECTOR_2D(1400.0, 540.0)) boss.iBossPatternState ++ ENDIF BREAK CASE 4 IF GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[iLeader]) IF (iMouthCover != GGSM_INVALID_ENTITY) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ELSE SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ENDIF GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_BREAD(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_BREAD_FACE) IF (iLeader = GGSM_INVALID_ENTITY) AND (boss.eState >= GGSM_BOSS_STATE_ARRIVE) EXIT ENDIF SWITCH (boss.eState) CASE GGSM_BOSS_STATE_ARRIVE IF (boss.bStateInit = FALSE) GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iLeader], INIT_VECTOR_2D(1400, 540)) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) boss.bStateInit = TRUE ELIF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLeader].eMoveFlags, GGSM_MOVE_BIT_COMPLETE) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[iLeader], GGSM_MOVEMENT_NONE) GGSM_DIALOG_CONTROLLER_START_DIALOG(sGGSMData.sDialogController, GGSM_DIALOG_BOSS_BREAD_START) GGSM_BOSS_CONTROLLER_SET_ATTACK_PATTERN(boss, GGSM_BOSS_STATE_PATTERN_A) ENDIF BREAK CASE GGSM_BOSS_STATE_ACTIVE IF GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[iLeader]) GGSM_BOSS_CONTROLLER_SELECT_ATTACK_PATTERN(boss) ENDIF BREAK CASE GGSM_BOSS_STATE_PATTERN_A GGSM_BOSS_CONTROLLER_UPDATE_BREAD_PATTERN_A(boss) BREAK CASE GGSM_BOSS_STATE_PATTERN_B GGSM_BOSS_CONTROLLER_UPDATE_BREAD_PATTERN_B(boss) BREAK CASE GGSM_BOSS_STATE_PATTERN_C GGSM_BOSS_CONTROLLER_UPDATE_BREAD_PATTERN_C(boss) BREAK CASE GGSM_BOSS_STATE_PATTERN_D CASE GGSM_BOSS_STATE_PATTERN_E GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) BREAK CASE GGSM_BOSS_STATE_PLAYER_DEAD IF (boss.bStateInit = FALSE) GGSM_DIALOG_CONTROLLER_START_DIALOG(sGGSMData.sDialogController, GGSM_DIALOG_BOSS_BREAD_FAILED) boss.bStateInit = TRUE ENDIF BREAK CASE GGSM_BOSS_STATE_DEAD IF (boss.bStateInit = FALSE) GGSM_DIALOG_CONTROLLER_START_DIALOG(sGGSMData.sDialogController, GGSM_DIALOG_BOSS_BREAD_DEFEATED) boss.bStateInit = TRUE ELIF NOT GGSM_IS_DIALOG_ACTIVE() GGSM_ENTITY_EXPLODE_ARRAY(sGGSMData.sEntities, FALSE) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_DONE) ENDIF BREAK ENDSWITCH ENDPROC //------------------------------------------------- // BOSS CONTROLLER GRANANA FUNCTION //------------------------------------------------- PROC GGSM_BOSS_CONTROLLER_GRANANA_CRACK_GLASSES(GGSM_BOSS_CONTROLLER &boss) INT iGlasses = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_GRANANA_GLASSES) IF (iGlasses = GGSM_INVALID_ENTITY) EXIT ENDIF GGSM_ENTITY_SET_ANIM_FRAME(sGGSMData.sEntities[iGlasses], 2, TRUE) GGSM_PLAY_SOUND_FROM_POSITION(ARCADE_GAMES_SOUND_GGSM_BOSS_GRAN_DAMAGE, sGGSMData.sEntities[iGlasses].sWorld.vPosition) CPRINTLN(DEBUG_MINIGAME, "GGSM_BOSS_CONTROLLER_GRANANA_CRACK_GLASSES") ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_GRANANA_PATTERN_A(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_GRANANA) INT iGlasses = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_GRANANA_GLASSES) INT iHair = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_GRANANA_HAIR) FLOAT fHPPerc = GGSM_BOSS_CONTROLLER_GET_HP_PERCENTAGE(boss) IF (iLeader = GGSM_INVALID_ENTITY) AND (boss.eState >= GGSM_BOSS_STATE_ARRIVE) EXIT ENDIF IF (fHPPerc > 0.5) sGGSMData.sEntities[iLeader].iNumShotsOverride = 2 ELSE sGGSMData.sEntities[iLeader].iNumShotsOverride = 4 ENDIF SWITCH (boss.iBossPatternState) CASE 0 ARCADE_GAMES_SOUND_STOP(ARCADE_GAMES_SOUND_GGSM_BOSS_GRAN_ATTACK_EYE_LASER_CHARGE_LOOP) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGlasses].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iHair].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ALT_SPREAD) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_GRANANASPREAD1) GGSM_ENTITY_RESET_BASE_SPEED(sGGSMData.sEntities[iGlasses]) IF (fHPPerc > 0.5) GGSM_ENTITY_SET_ANIM_FRAME(sGGSMData.sEntities[iGlasses], 0, TRUE) GGSM_ENTITY_SCALE_BASE_SPEED(sGGSMData.sEntities[iGlasses], 2.0) ELSE GGSM_ENTITY_SET_ANIM_FRAME(sGGSMData.sEntities[iGlasses], 2, TRUE) ENDIF boss.iInternalCounter = GET_RANDOM_INT_IN_RANGE(6, 12) boss.iBossPatternState ++ BREAK CASE 1 IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_FIRED_THIS_FRAME) boss.iInternalCounter -- IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_FIRED_ALT_SPREAD) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_GRANANASPREAD1A) ELSE GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_GRANANASPREAD1) ENDIF ENDIF IF GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[iLeader]) IF (boss.iInternalCounter > 0) GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iLeader], INIT_VECTOR_2D(GET_RANDOM_FLOAT_IN_RANGE(1200, 1450), GET_RANDOM_FLOAT_IN_RANGE(500, 740))) ELSE boss.iBossPatternState ++ ENDIF ENDIF BREAK CASE 2 GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_GRANANA_PATTERN_B(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_GRANANA) INT iGlasses = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_GRANANA_GLASSES) INT iHair = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_GRANANA_HAIR) FLOAT fHPPerc = GGSM_BOSS_CONTROLLER_GET_HP_PERCENTAGE(boss) IF (iLeader = GGSM_INVALID_ENTITY) AND (boss.eState >= GGSM_BOSS_STATE_ARRIVE) EXIT ENDIF IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_FIRED_THIS_FRAME) IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_FIRED_ALT_SPREAD) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_GRANANASPREAD1A) ELSE GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_GRANANASPREAD1) ENDIF ENDIF SWITCH (boss.iBossPatternState) CASE 0 GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iLeader], INIT_VECTOR_2D(1355, 900)) GGSM_ENTITY_SCALE_BASE_SPEED(sGGSMData.sEntities[iLeader], 3.0) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGlasses].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iHair].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) boss.iBossPatternState ++ BREAK CASE 1 IF GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[iLeader]) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[iLeader], GGSM_MOVEMENT_NONE) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_GRANANASPREAD1) GGSM_ENTITY_DETACH_FROM_PARENT(sGGSMData.sEntities[iHair]) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iHair], GGSM_WEAPON_GRANANAHAIR) GGSM_PLAY_SOUND_FROM_POSITION(ARCADE_GAMES_SOUND_GGSM_BOSS_GRAN_DAMAGE_LOSE_WIG, sGGSMData.sEntities[iHair].sWorld.vPosition) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iHair].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iHair].eFlags, GGSM_ENTITY_BIT_WPN_FIRE_ON_ARRIVE) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[iHair], GGSM_MOVEMENT_TARGETTED_WANDER, 0.125) IF (fHPPerc < 0.5) sGGSMData.sEntities[iHair].iNumShotsOverride = 6 GGSM_ENTITY_SCALE_BASE_SPEED(sGGSMData.sEntities[iHair], 1.5) ENDIF boss.iInternalCounter = GET_RANDOM_INT_IN_RANGE(4, 6) boss.iBossPatternState ++ ENDIF BREAK CASE 2 IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iHair].eMoveFlags, GGSM_MOVE_BIT_TARGET_POINT_REACHED_THIS_FRAME) boss.iInternalCounter -- ENDIF IF (boss.iInternalCounter <= 0) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iHair], GGSM_WEAPON_NONE) GGSM_ENTITY_ATTACH_TO_PARENT(sGGSMData.sEntities[iHair], sGGSMData.sEntities[iLeader]) GGSM_ENTITY_RETURN_TO_ORIGIN(sGGSMData.sEntities[iHair]) GGSM_ENTITY_RESET_BASE_SPEED(sGGSMData.sEntities[iHair]) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iHair].eFlags, GGSM_ENTITY_BIT_WPN_FIRE_ON_ARRIVE) GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iLeader], INIT_VECTOR_2D(1450, 540)) GGSM_ENTITY_RESET_BASE_SPEED(sGGSMData.sEntities[iLeader]) boss.iBossPatternState ++ ENDIF BREAK CASE 3 IF GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[iLeader]) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_GRANANA_PATTERN_C(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_GRANANA) INT iGlasses = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_GRANANA_GLASSES) FLOAT fHPPerc = GGSM_BOSS_CONTROLLER_GET_HP_PERCENTAGE(boss) IF (iLeader = GGSM_INVALID_ENTITY) AND (boss.eState >= GGSM_BOSS_STATE_ARRIVE) EXIT ENDIF SWITCH (boss.iBossPatternState) CASE 0 ARCADE_GAMES_SOUND_PLAY_LOOP(ARCADE_GAMES_SOUND_GGSM_BOSS_GRAN_ATTACK_EYE_LASER_CHARGE_LOOP) IF (fHPPerc > 0.5) GGSM_ENTITY_SET_ANIMATION(sGGSMData.sEntities[iGlasses], GGSM_SPRITE_ANIM_GRAN_GLASS) ELSE GGSM_ENTITY_SET_ANIMATION(sGGSMData.sEntities[iGlasses], GGSM_SPRITE_ANIM_GRAN_GLASSCRACK) ENDIF boss.iBossPatternState ++ BREAK CASE 1 IF (boss.fStateTimer > 3.0) IF (fHPPerc > 0.5) GGSM_ENTITY_SET_ANIM_FRAME(sGGSMData.sEntities[iGlasses], 1, TRUE) ELSE GGSM_ENTITY_SET_ANIM_FRAME(sGGSMData.sEntities[iGlasses], 3, TRUE) ENDIF GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[iLeader], GGSM_MOVEMENT_NONE) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGlasses].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) boss.iBossPatternState ++ boss.fStateTimer = 0.0 ENDIF BREAK CASE 2 IF (boss.fStateTimer > 1.0) ARCADE_GAMES_SOUND_STOP(ARCADE_GAMES_SOUND_GGSM_BOSS_GRAN_ATTACK_EYE_LASER_CHARGE_LOOP) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGlasses].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) IF (fHPPerc < 0.5) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iGlasses], GGSM_WEAPON_GRANANAGLASSES2) ELSE GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iGlasses], GGSM_WEAPON_GRANANAGLASSES) ENDIF GGSM_ENTITY_FIRE_WEAPON(sGGSMData.sEntities[iGlasses]) boss.iBossPatternState ++ ENDIF BREAK CASE 3 IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iGlasses].eFlags, GGSM_ENTITY_BIT_WPN_BURST_FIRED) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_GRANANA(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_GRANANA) INT iGlasses = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_GRANANA_GLASSES) IF (iLeader = GGSM_INVALID_ENTITY) AND (boss.eState >= GGSM_BOSS_STATE_ARRIVE) EXIT ENDIF IF (boss.eState > GGSM_BOSS_STATE_ARRIVE) IF (boss.bFiftyPercent = FALSE) AND (GGSM_BOSS_CONTROLLER_GET_HP_PERCENTAGE(boss) < 0.5) GGSM_BOSS_CONTROLLER_GRANANA_CRACK_GLASSES(boss) boss.bFiftyPercent = TRUE ENDIF ENDIF SWITCH (boss.eState) CASE GGSM_BOSS_STATE_ARRIVE IF (boss.bStateInit = FALSE) GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iLeader], INIT_VECTOR_2D(1450, 540)) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGlasses].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) boss.bStateInit = TRUE ELIF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLeader].eMoveFlags, GGSM_MOVE_BIT_COMPLETE) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[iLeader], GGSM_MOVEMENT_NONE) GGSM_BOSS_CONTROLLER_SET_ATTACK_PATTERN(boss, GGSM_BOSS_STATE_PATTERN_A) GGSM_DIALOG_CONTROLLER_START_DIALOG(sGGSMData.sDialogController, GGSM_DIALOG_BOSS_GRANANA_START) ENDIF BREAK CASE GGSM_BOSS_STATE_ACTIVE IF GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[iLeader]) GGSM_BOSS_CONTROLLER_SELECT_ATTACK_PATTERN(boss) ENDIF BREAK CASE GGSM_BOSS_STATE_PATTERN_A GGSM_BOSS_CONTROLLER_UPDATE_GRANANA_PATTERN_A(boss) BREAK CASE GGSM_BOSS_STATE_PATTERN_B GGSM_BOSS_CONTROLLER_UPDATE_GRANANA_PATTERN_B(boss) BREAK CASE GGSM_BOSS_STATE_PATTERN_C GGSM_BOSS_CONTROLLER_UPDATE_GRANANA_PATTERN_C(boss) BREAK CASE GGSM_BOSS_STATE_PATTERN_D CASE GGSM_BOSS_STATE_PATTERN_E GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) BREAK CASE GGSM_BOSS_STATE_PLAYER_DEAD IF (boss.bStateInit = FALSE) ARCADE_GAMES_SOUND_STOP(ARCADE_GAMES_SOUND_GGSM_BOSS_GRAN_ATTACK_EYE_LASER_CHARGE_LOOP) GGSM_DIALOG_CONTROLLER_START_DIALOG(sGGSMData.sDialogController, GGSM_DIALOG_BOSS_GRANANA_FAILED) boss.bStateInit = TRUE ENDIF BREAK CASE GGSM_BOSS_STATE_DEAD IF (boss.bStateInit = FALSE) ARCADE_GAMES_SOUND_STOP(ARCADE_GAMES_SOUND_GGSM_BOSS_GRAN_ATTACK_EYE_LASER_CHARGE_LOOP) GGSM_DIALOG_CONTROLLER_START_DIALOG(sGGSMData.sDialogController, GGSM_DIALOG_BOSS_GRANANA_DEFEATED) boss.bStateInit = TRUE ELIF NOT GGSM_IS_DIALOG_ACTIVE() GGSM_ENTITY_EXPLODE_ARRAY(sGGSMData.sEntities, FALSE) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_DONE) ENDIF BREAK ENDSWITCH ENDPROC //------------------------------------------------- // BOSS CONTROLLER MARINE FUNCTION //------------------------------------------------- PROC GGSM_BOSS_CONTROLLER_MARINE_CHESTBURST(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_MARINE) IF (iLeader = GGSM_INVALID_ENTITY) EXIT ENDIF GGSM_ENTITY_SET_ANIMATION(sGGSMData.sEntities[iLeader], GGSM_SPRITE_ANIM_MARINE_ALIEN) GGSM_PLAY_SOUND_FROM_POSITION(ARCADE_GAMES_SOUND_GGSM_BOSS_MARINE_CHESTBURST, sGGSMData.sEntities[iLeader].sWorld.vPosition) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_MARINE_PATTERN_A(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_MARINE) INT iLauncher = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_MARINE_LAUNCHER) IF (GGSM_BOSS_CONTROLLER_GET_HP_PERCENTAGE(boss) < 0.5) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF IF (iLeader = GGSM_INVALID_ENTITY) OR (iLauncher = GGSM_INVALID_ENTITY) EXIT ENDIF SWITCH (boss.iBossPatternState) CASE 0 IF (boss.fStateTimer > 0.5) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLauncher].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_MARINE_SPREAD) boss.iBossPatternState ++ boss.iInternalCounter = GET_RANDOM_INT_IN_RANGE(7, 11) ENDIF BREAK CASE 1 IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_FIRED_THIS_FRAME) boss.iInternalCounter -- ENDIF IF (boss.iInternalCounter <= 0) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) boss.iBossPatternState ++ boss.fStateTimer = 0 ENDIF BREAK CASE 2 IF (boss.fStateTimer > 0.5) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_MARINE_PATTERN_B(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_MARINE) INT iLauncher = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_MARINE_LAUNCHER) IF (GGSM_BOSS_CONTROLLER_GET_HP_PERCENTAGE(boss) < 0.5) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF IF (iLeader = GGSM_INVALID_ENTITY) OR (iLauncher = GGSM_INVALID_ENTITY) EXIT ENDIF SWITCH (boss.iBossPatternState) CASE 0 IF (boss.fStateTimer > 0.5) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLauncher].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLauncher], GGSM_WEAPON_MARINE_LAUNCHER) boss.iBossPatternState ++ boss.iInternalCounter = GET_RANDOM_INT_IN_RANGE(5, 10) ENDIF BREAK CASE 1 IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLauncher].eFlags, GGSM_ENTITY_BIT_WPN_FIRED_THIS_FRAME) boss.iInternalCounter -- ENDIF IF (boss.iInternalCounter <= 0) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLauncher].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) boss.iBossPatternState ++ boss.fStateTimer = 0 ENDIF BREAK CASE 2 IF (sGGSMData.iEnemyProjectilesActive = 0) boss.iBossPatternState ++ boss.fStateTimer = 0 ENDIF BREAK CASE 3 IF (boss.fStateTimer > 0.1) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_MARINE_PATTERN_C(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_MARINE) INT iLauncher = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_MARINE_LAUNCHER) FLOAT hprc = GGSM_BOSS_CONTROLLER_GET_HP_PERCENTAGE(boss) IF (hprc > 0.5) OR (hprc < 0.25) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF IF (iLeader = GGSM_INVALID_ENTITY) EXIT ENDIF SWITCH (boss.iBossPatternState) CASE 0 IF (boss.fStateTimer > 0.5) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLauncher].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_RANDOM_SPREAD) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_SINGLE_SHOT_MODE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_ACID_VULKAN) boss.iBossPatternState ++ boss.iInternalCounter = GET_RANDOM_INT_IN_RANGE(10, 15) ENDIF BREAK CASE 1 IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_FIRED_THIS_FRAME) boss.iInternalCounter -- ENDIF IF (boss.iInternalCounter <= 0) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) boss.iBossPatternState ++ boss.fStateTimer = 0 ENDIF BREAK CASE 2 IF (boss.fStateTimer > 0.5) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_MARINE_PATTERN_D(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_MARINE) INT iLauncher = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_MARINE_LAUNCHER) IF (GGSM_BOSS_CONTROLLER_GET_HP_PERCENTAGE(boss) > 0.25) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF IF (iLeader = GGSM_INVALID_ENTITY) EXIT ENDIF SWITCH (boss.iBossPatternState) CASE 0 IF (boss.fStateTimer > 0.5) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLauncher].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_RANDOM_SPREAD) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_SINGLE_SHOT_MODE) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_ACID) boss.iBossPatternState ++ boss.iInternalCounter = GET_RANDOM_INT_IN_RANGE(10, 15) ENDIF BREAK CASE 1 IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_FIRED_THIS_FRAME) boss.iInternalCounter -- ENDIF IF (boss.iInternalCounter <= 0) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) boss.iBossPatternState ++ boss.fStateTimer = 0 ENDIF BREAK CASE 2 IF (boss.fStateTimer > 0.5) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_MARINE(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_MARINE) IF (iLeader = GGSM_INVALID_ENTITY) AND (boss.eState >= GGSM_BOSS_STATE_ARRIVE) EXIT ENDIF IF (boss.bFiftyPercent = FALSE) IF (iLeader != GGSM_INVALID_ENTITY) AND (boss.eState > GGSM_BOSS_STATE_ARRIVE) IF (GGSM_BOSS_CONTROLLER_GET_HP_PERCENTAGE(boss) < 0.5) GGSM_BOSS_CONTROLLER_MARINE_CHESTBURST(boss) boss.bFiftyPercent = TRUE ENDIF ENDIF ENDIF SWITCH (boss.eState) CASE GGSM_BOSS_STATE_ARRIVE IF (boss.bStateInit = FALSE) GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iLeader], INIT_VECTOR_2D(1350, 540)) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ALT_SPREAD) boss.bStateInit = TRUE ELIF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLeader].eMoveFlags, GGSM_MOVE_BIT_COMPLETE) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[iLeader], GGSM_MOVEMENT_NONE) GGSM_BOSS_CONTROLLER_SET_ATTACK_PATTERN(boss, GGSM_BOSS_STATE_PATTERN_A) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_ENEMYCONESPREAD) GGSM_DIALOG_CONTROLLER_START_DIALOG(sGGSMData.sDialogController, GGSM_DIALOG_BOSS_MARINE_START) ENDIF BREAK CASE GGSM_BOSS_STATE_ACTIVE IF GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[iLeader]) GGSM_BOSS_CONTROLLER_SELECT_ATTACK_PATTERN(boss) ENDIF BREAK CASE GGSM_BOSS_STATE_PATTERN_A GGSM_BOSS_CONTROLLER_UPDATE_MARINE_PATTERN_A(boss) BREAK CASE GGSM_BOSS_STATE_PATTERN_B GGSM_BOSS_CONTROLLER_UPDATE_MARINE_PATTERN_B(boss) BREAK CASE GGSM_BOSS_STATE_PATTERN_C GGSM_BOSS_CONTROLLER_UPDATE_MARINE_PATTERN_C(boss) BREAK CASE GGSM_BOSS_STATE_PATTERN_D GGSM_BOSS_CONTROLLER_UPDATE_MARINE_PATTERN_D(boss) BREAK CASE GGSM_BOSS_STATE_PATTERN_E GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) BREAK CASE GGSM_BOSS_STATE_PLAYER_DEAD IF (boss.bStateInit = FALSE) GGSM_DIALOG_CONTROLLER_START_DIALOG(sGGSMData.sDialogController, GGSM_DIALOG_BOSS_MARINE_FAILED) boss.bStateInit = TRUE ENDIF BREAK CASE GGSM_BOSS_STATE_DEAD IF (boss.bStateInit = FALSE) GGSM_DIALOG_CONTROLLER_START_DIALOG(sGGSMData.sDialogController, GGSM_DIALOG_BOSS_MARINE_DEFEATED) boss.bStateInit = TRUE ELIF NOT GGSM_IS_DIALOG_ACTIVE() GGSM_ENTITY_EXPLODE_ARRAY(sGGSMData.sEntities, FALSE) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_DONE) ENDIF BREAK ENDSWITCH ENDPROC //------------------------------------------------- // BOSS CONTROLLER DR_DANK FUNCTION //------------------------------------------------- PROC GGSM_BOSS_CONTROLLER_DR_DANK_ACTIVATE_ROCKETS(GGSM_BOSS_CONTROLLER &boss, BOOL bOn = TRUE) INT i, ind REPEAT 4 i ind = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_DR_DANK_ROCKET_L1 + i) IF (ind != GGSM_INVALID_ENTITY) AND (sGGSMData.sEntities[ind].eState = GGSM_ENTITY_STATE_ALIVE) IF (bOn) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[ind].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ELSE CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[ind].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ENDIF ENDIF ENDREPEAT ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_DR_DANK_PATTERN_A(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_DR_DANK_TOP) INT iGunSection = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_DR_DANK_BOTTOM) VECTOR_2D vTarget, vPlayerPos IF (iLeader = GGSM_INVALID_ENTITY) EXIT ENDIF IF (iGunSection = GGSM_INVALID_ENTITY) GGSM_BOSS_CONTROLLER_SELECT_ATTACK_PATTERN(boss) EXIT ENDIF SWITCH (boss.iBossPatternState) CASE 0 // detach gun GGSM_BOSS_CONTROLLER_DEACTIVATE_ALL_WEAPONS(boss) GGSM_ENTITY_DETACH_FROM_PARENT(sGGSMData.sEntities[iGunSection]) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iGunSection], GGSM_WEAPON_DANK_CANNON) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGunSection].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iGunSection], INIT_VECTOR_2D(1890, 820)) boss.iBossPatternState ++ BREAK CASE 1 // move gun to top of screen and move down wards IF GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[iGunSection]) GGSM_ENTITY_SET_LOCAL_TRANSFORM(sGGSMData.sEntities[iGunSection], 1470, 0, 270) GGSM_ENTITY_SET_ANIMATION(sGGSMData.sEntities[iGunSection], GGSM_SPRITE_ANIM_DANK_CANNON) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGunSection].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iGunSection], INIT_VECTOR_2D(1470, 70), 0.125) boss.iInternalCounter = GET_RANDOM_INT_IN_RANGE(2, 5) boss.iBossPatternState ++ ENDIF BREAK CASE 2 // start moving gun across IF GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[iGunSection]) boss.iInternalCounter = GET_RANDOM_INT_IN_RANGE(2, 5) GGSM_BOSS_CONTROLLER_DR_DANK_ACTIVATE_ROCKETS(boss, TRUE) GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iGunSection], INIT_VECTOR_2D(390, 70)) boss.iBossPatternState ++ ENDIF BREAK CASE 3 // if player cross the line of gun shoot - if we've moved across so many times the return gun vPlayerPos = GGSM_GET_TARGET_AT_PLAYER_POSITION() IF (ABSF(vPlayerPos.x - sGGSMData.sEntities[iGunSection].sWorld.vPosition.x) < 128.0) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGunSection].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ELSE CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGunSection].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ENDIF IF GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[iGunSection]) boss.iInternalCounter -- vTarget = sGGSMData.sEntities[iGunSection].sWorld.vPosition IF (boss.iInternalCounter <= 0) vTarget = sGGSMData.sEntities[iGunSection].sWorld.vPosition vTarget.y -= 100.0 GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iGunSection], vTarget) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGunSection].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) boss.iBossPatternState ++ EXIT ENDIF IF (sGGSMData.sEntities[iGunSection].vLocalDirection.x < 0) GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iGunSection], INIT_VECTOR_2D(1470, vTarget.y)) ELSE GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iGunSection], INIT_VECTOR_2D(390, vTarget.y)) ENDIF ENDIF BREAK CASE 4 // put gun back IF GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[iGunSection]) GGSM_ENTITY_SET_ANIM_FRAME(sGGSMData.sEntities[iGunSection], DEFAULT, TRUE) GGSM_ENTITY_SET_LOCAL_TRANSFORM(sGGSMData.sEntities[iGunSection], 1890, 820, 0) GGSM_ENTITY_SET_PARENT_INDEX(sGGSMData.sEntities[iGunSection], iLeader) GGSM_ENTITY_RETURN_TO_ORIGIN(sGGSMData.sEntities[iGunSection]) boss.iBossPatternState ++ ENDIF BREAK CASE 5 // turn rockets off IF GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[iGunSection]) GGSM_BOSS_CONTROLLER_DR_DANK_ACTIVATE_ROCKETS(boss, FALSE) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_DR_DANK_PATTERN_B(GGSM_BOSS_CONTROLLER &boss) INT iGunSection = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_DR_DANK_MIDDLE) IF (iGunSection = GGSM_INVALID_ENTITY) GGSM_BOSS_CONTROLLER_SELECT_ATTACK_PATTERN(boss) EXIT ENDIF SWITCH (boss.iBossPatternState) CASE 0 GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iGunSection], GGSM_WEAPON_DANK_CLUSTERBOMB) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGunSection].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGunSection].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) sGGSMData.sEntities[iGunSection].iNumShotsOverride = 4 boss.iBossPatternState ++ boss.iInternalCounter = GET_RANDOM_INT_IN_RANGE(4, 8) BREAK CASE 1 IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iGunSection].eFlags, GGSM_ENTITY_BIT_WPN_FIRED_THIS_FRAME) boss.iInternalCounter -- ENDIF IF (boss.iInternalCounter < 0) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGunSection].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_DR_DANK_PATTERN_C(GGSM_BOSS_CONTROLLER &boss) INT iGunSection = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_DR_DANK_MIDDLE) IF (iGunSection = GGSM_INVALID_ENTITY) GGSM_BOSS_CONTROLLER_SELECT_ATTACK_PATTERN(boss) EXIT ENDIF SWITCH (boss.iBossPatternState) CASE 0 GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iGunSection], GGSM_WEAPON_DANK_SPREAD) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGunSection].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGunSection].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGunSection].eFlags, GGSM_ENTITY_BIT_WPN_ALT_SPREAD) sGGSMData.sEntities[iGunSection].iNumShotsOverride = 4 boss.iBossPatternState ++ boss.iInternalCounter = GET_RANDOM_INT_IN_RANGE(4, 8) BREAK CASE 1 IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iGunSection].eFlags, GGSM_ENTITY_BIT_WPN_FIRED_THIS_FRAME) boss.iInternalCounter -- ENDIF IF (boss.iInternalCounter < 0) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGunSection].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_DR_DANK_PATTERN_D(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_DR_DANK_TOP) INT iGunSection = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_DR_DANK_BOTTOM) IF (iLeader = GGSM_INVALID_ENTITY) GGSM_BOSS_CONTROLLER_SELECT_ATTACK_PATTERN(boss) EXIT ENDIF SWITCH (boss.iBossPatternState) CASE 0 IF (iGunSection != GGSM_INVALID_ENTITY) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iGunSection], GGSM_WEAPON_DANK_CANNON) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGunSection].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iGunSection].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) ENDIF GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeader], GGSM_WEAPON_DANK_SCATTER) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) boss.iBossPatternState ++ boss.iInternalCounter = GET_RANDOM_INT_IN_RANGE(10, 15) BREAK CASE 1 IF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_FIRED_THIS_FRAME) boss.iInternalCounter -- ENDIF IF (boss.iInternalCounter < 0) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ACTIVE) ENDIF BREAK ENDSWITCH ENDPROC PROC GGSM_BOSS_CONTROLLER_UPDATE_DR_DANK(GGSM_BOSS_CONTROLLER &boss) INT iLeader = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_DR_DANK_TOP) //INT iGunSection = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, GGSM_BOSS_SECTION_DR_DANK_BOTTOM) IF (iLeader = GGSM_INVALID_ENTITY) AND (boss.eState >= GGSM_BOSS_STATE_ARRIVE) EXIT ENDIF SWITCH (boss.eState) CASE GGSM_BOSS_STATE_ARRIVE IF (boss.bStateInit = FALSE) GGSM_ENTITY_SET_MOVEMENT_TO_VECTOR(sGGSMData.sEntities[iLeader], INIT_VECTOR_2D(1350, 540)) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeader].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) boss.bStateInit = TRUE ELIF IS_BITMASK_ENUM_AS_ENUM_SET(sGGSMData.sEntities[iLeader].eMoveFlags, GGSM_MOVE_BIT_COMPLETE) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[iLeader], GGSM_MOVEMENT_NONE) GGSM_BOSS_CONTROLLER_SET_ATTACK_PATTERN(boss, GGSM_BOSS_STATE_PATTERN_A) GGSM_DIALOG_CONTROLLER_START_DIALOG(sGGSMData.sDialogController, GGSM_DIALOG_BOSS_DR_DANK_START) ENDIF BREAK CASE GGSM_BOSS_STATE_ACTIVE IF GGSM_ENTITY_IS_MOVEMENT_COMPLETE(sGGSMData.sEntities[iLeader]) GGSM_BOSS_CONTROLLER_SELECT_ATTACK_PATTERN(boss) ENDIF BREAK CASE GGSM_BOSS_STATE_PATTERN_A GGSM_BOSS_CONTROLLER_UPDATE_DR_DANK_PATTERN_A(boss) BREAK CASE GGSM_BOSS_STATE_PATTERN_B GGSM_BOSS_CONTROLLER_UPDATE_DR_DANK_PATTERN_B(boss) BREAK CASE GGSM_BOSS_STATE_PATTERN_C GGSM_BOSS_CONTROLLER_UPDATE_DR_DANK_PATTERN_C(boss) BREAK CASE GGSM_BOSS_STATE_PATTERN_D GGSM_BOSS_CONTROLLER_UPDATE_DR_DANK_PATTERN_D(boss) BREAK CASE GGSM_BOSS_STATE_PATTERN_E GGSM_BOSS_CONTROLLER_SELECT_ATTACK_PATTERN(boss) BREAK CASE GGSM_BOSS_STATE_PLAYER_DEAD IF (boss.bStateInit = FALSE) GGSM_DIALOG_CONTROLLER_START_DIALOG(sGGSMData.sDialogController, GGSM_DIALOG_BOSS_DR_DANK_FAILED) boss.bStateInit = TRUE ENDIF BREAK CASE GGSM_BOSS_STATE_DEAD IF (boss.bStateInit = FALSE) GGSM_DIALOG_CONTROLLER_START_DIALOG(sGGSMData.sDialogController, GGSM_DIALOG_BOSS_DR_DANK_DEFEATED) boss.bStateInit = TRUE ELIF NOT GGSM_IS_DIALOG_ACTIVE() GGSM_ENTITY_EXPLODE_ARRAY(sGGSMData.sEntities, FALSE) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_DONE) ENDIF BREAK ENDSWITCH ENDPROC //------------------------------------------------- // BOSS CONTROLLER FUNCTION //------------------------------------------------- FUNC BOOL GGSM_BOSS_CONTROLLER_UPDATE(GGSM_BOSS_CONTROLLER &boss) INT i, ind IF (boss.eType = GGSM_BOSS_NONE) RETURN FALSE ENDIF IF (boss.eState = GGSM_BOSS_STATE_DONE) RETURN FALSE ENDIF boss.fStateTimer += (GET_FRAME_TIME() * sGGSMData.fTimeScale) boss.iTotalHP = GGSM_BOSS_CONTROLLER_GET_HP(boss) // don't let people shoot while the boss is loading IF (boss.eState >= GGSM_BOSS_STATE_LOADING) AND (boss.eState < GGSM_BOSS_STATE_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_DISABLE_WEAPONS) GGSM_SET_PLAYER_INVUNERABLE() ELSE CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_DISABLE_WEAPONS) ENDIF // handle defeated player state IF (boss.eState != GGSM_BOSS_STATE_PLAYER_DEAD) IF GGSM_IS_PLAYER_TOTALLY_DEFEATED() GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_PLAYER_DEAD) ENDIF ENDIF // handle boss dead state IF (boss.eState != GGSM_BOSS_STATE_DEAD) IF (boss.iMaxTotalHP > 0) AND (boss.iTotalHP = 0) boss.iMaxTotalHP = 0 GGSM_RESET_PROJECTILE_ARRAY(sGGSMData.sProjectiles) IF (boss.iSubGroupID != GGSM_INVALID_GROUP_ID) GGSM_DETONATE_ENTITY_GROUP(sGGSMData.sEntityGroup[boss.iSubGroupID]) boss.iSubGroupID = GGSM_INVALID_GROUP_ID ENDIF ARCADE_GAMES_SOUND_STOP(ARCADE_GAMES_SOUND_GGSM_BOSS_GRAN_ATTACK_EYE_LASER_CHARGE_LOOP) GGSM_ENTITY_EXPLODE_ARRAY(sGGSMData.sEntities, FALSE) GGSM_TRIGGER_MUSIC_EVENT("ARCADE_SM_STOP") GGSM_SHUTDOWN_ALL_SPECIAL_WEAPONS(sGGSMData.sSpWeaponData) IF boss.eType = GGSM_BOSS_DR_DANK GGSM_PLAY_AVATAR_ALL_CLEAR_ANIM() ELSE GGSM_PLAY_AVATAR_BOSS_DEAD_ANIM() ENDIF SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_PLAYER_BOSS_INVUNERABLE) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_DEAD) ENDIF ELSE IF (boss.fStateTimer > 15.0) SCRIPT_ASSERT("EMERGENCY TIME OUT") GGSM_DESTROY_ENTITIES_OF_FACTION(FALSE) ENDIF ENDIF // remove dead units from the boss controller IF (boss.iMaxTotalHP > 0) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_BRING_CAMERA_TO_STOP) REPEAT GGSM_MAX_BOSS_PARTS i ind = GGSM_BOSS_CONTROLLER_GET_ENTITY_INDEX(boss, i) IF (ind != GGSM_INVALID_ENTITY) IF (sGGSMData.sEntities[ind].eState != GGSM_ENTITY_STATE_ALIVE) GGSM_BOSS_CONTROLLER_SET_ENTITY_INDEX(boss, i, GGSM_INVALID_ENTITY) ENDIF ENDIF ENDREPEAT ENDIF // update standard states SWITCH (boss.eState) CASE GGSM_BOSS_STATE_NONE GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_LOADING) BREAK CASE GGSM_BOSS_STATE_LOADING IF GGSM_LOAD_TEXTURE_DICTS_FOR_BOSS(boss.eType) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_CREATE) ENDIF BREAK CASE GGSM_BOSS_STATE_CREATE IF GGSM_BOSS_INIT(boss) GGSM_CLEAR_BOSS_CONTROLLER_USED_PATTERN_BITSET(boss) GGSM_BOSS_CONTROLLER_SET_STATE(boss, GGSM_BOSS_STATE_ARRIVE) ENDIF BREAK ENDSWITCH // update boss specific states SWITCH (boss.eType) CASE GGSM_BOSS_BREAD GGSM_BOSS_CONTROLLER_UPDATE_BREAD(boss) BREAK CASE GGSM_BOSS_DR_DANK GGSM_BOSS_CONTROLLER_UPDATE_DR_DANK(boss) BREAK CASE GGSM_BOSS_GRANANA GGSM_BOSS_CONTROLLER_UPDATE_GRANANA(boss) BREAK CASE GGSM_BOSS_MARINE GGSM_BOSS_CONTROLLER_UPDATE_MARINE(boss) BREAK CASE GGSM_BOSS_SMOOTHIE GGSM_BOSS_CONTROLLER_UPDATE_SMOOTHIE(boss) BREAK ENDSWITCH RETURN TRUE ENDFUNC PROC GGSM_BOSS_CONTROLLER_UPDATE_ARRAY(GGSM_BOSS_CONTROLLER &array[]) INT i REPEAT COUNT_OF(array) i IF GGSM_BOSS_CONTROLLER_UPDATE(array[i]) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.eStageFlags, GGSM_STAGE_BIT_BOSSES_ACTIVE) ENDIF ENDREPEAT ENDPROC //------------------------------------------------- // GROUP UPDATE FUNCTIONS //------------------------------------------------- PROC GGSM_ENTITY_GROUP_UPDATE_FORMATION_STANDARD(GGSM_ENTITY_GROUP &group) GGSM_ENTITY_TYPE entType = GGSM_FORMATION_GET_ENTITY_TYPE(group.sFormSettings) GGSM_ENTITY_DATA entData = GGSM_ENTITY_DATA_GET(entType) VECTOR_2D spriteSize = GGSM_GET_SPRITE_SIZE(entData.eSpriteType) VECTOR_2D spacing = GGSM_FORMATION_GET_SPACING(group.sFormSettings) FLOAT fDistBetweenUnits = FMAX(ABSF(spriteSize.x), ABSF(spriteSize.y)) * spacing.x FLOAT spd = entData.fBaseSpeed // move the dist counter so we can ensure the formation is reasonably spaced group.fDistCounter += (spd * GET_FRAME_TIME() * sGGSMData.fTimeScale) group.fDistCounter = CLAMP(group.fDistCounter, 0, fDistBetweenUnits) IF (group.fDistCounter < fDistBetweenUnits) EXIT ENDIF INT ind VECTOR_2D vBasePos // create leader IF NOT GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) EXIT ENDIF vBasePos = GGSM_FORMATION_GET_START_POSITION(group.sFormSettings) GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], entType, vBasePos, 0) sGGSMData.sEntities[ind].vLocalDirection = GGSM_FORMATION_GET_START_DIRECTION(group.sFormSettings) sGGSMData.sEntities[ind].fSpeed = spd group.fDistCounter = 0 GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[ind], group.iGroupID) GGSM_ENTITY_CONFIGURE_FROM_FORMATION(sGGSMData.sEntities[ind], group.sFormSettings) ENDPROC PROC GGSM_ENTITY_GROUP_UPDATE_FORMATION_DELAYED_LINE(GGSM_ENTITY_GROUP &group, VECTOR_2D vSpreadDir) GGSM_ENTITY_TYPE entType = GGSM_FORMATION_GET_ENTITY_TYPE(group.sFormSettings) GGSM_ENTITY_DATA entData = GGSM_ENTITY_DATA_GET(entType) VECTOR_2D spriteSize = GGSM_GET_SPRITE_SIZE(entData.eSpriteType) VECTOR_2D spacing = GGSM_FORMATION_GET_SPACING(group.sFormSettings) FLOAT fDistBetweenUnits = FMAX(ABSF(spriteSize.x), ABSF(spriteSize.y)) * spacing.x FLOAT spd = entData.fBaseSpeed // move the dist counter so we can ensure the formation is reasonably spaced group.fDistCounter += (spd * GET_FRAME_TIME() * sGGSMData.fTimeScale) group.fDistCounter = CLAMP(group.fDistCounter, 0, fDistBetweenUnits) IF (group.fDistCounter < fDistBetweenUnits) EXIT ENDIF INT ind // create leader IF NOT GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) EXIT ENDIF INT iFormIndex = GGSM_FORMATION_GET_MEMBER_COUNT(group.sFormSettings) - group.iMembersToCreate VECTOR_2D vBasePos = GGSM_FORMATION_GET_POSITION_FOR_DELAYED_LINE(group.sFormSettings, vSpreadDir, iFormIndex, spriteSize) GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], entType, vBasePos, 0) sGGSMData.sEntities[ind].vLocalDirection = GGSM_FORMATION_GET_START_DIRECTION(group.sFormSettings) sGGSMData.sEntities[ind].fSpeed = spd group.fDistCounter = 0 GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[ind], group.iGroupID) GGSM_ENTITY_CONFIGURE_FROM_FORMATION(sGGSMData.sEntities[ind], group.sFormSettings) ENDPROC PROC GGSM_ENTITY_GROUP_UPDATE_FORMATION_HORZLINE(GGSM_ENTITY_GROUP &group) INT i, ind VECTOR_2D vDir = GGSM_FORMATION_GET_START_DIRECTION(group.sFormSettings) VECTOR_2D vStoredOrigin VECTOR_2D vStartPos = GGSM_FORMATION_GET_START_POSITION(group.sFormSettings) VECTOR_2D vBasePos = vStartPos FLOAT fDist GGSM_ENTITY_TYPE entType = GGSM_FORMATION_GET_ENTITY_TYPE(group.sFormSettings) GGSM_ENTITY_DATA entData = GGSM_ENTITY_DATA_GET(entType) VECTOR_2D spriteSize = GGSM_GET_SPRITE_SIZE(entData.eSpriteType) VECTOR_2D spacing = GGSM_FORMATION_GET_SPACING(group.sFormSettings) FLOAT fDistBetweenUnits = ABSF(spriteSize.x) * spacing.x FLOAT spd = entData.fBaseSpeed fDist = 0 REPEAT group.sFormSettings.iFormationMembers i IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], entType, vBasePos, 0) sGGSMData.sEntities[ind].vLocalDirection = vDir sGGSMData.sEntities[ind].fSpeed = spd GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[ind], group.iGroupID) GGSM_ENTITY_CONFIGURE_FROM_FORMATION(sGGSMData.sEntities[ind], group.sFormSettings) vStoredOrigin = vStartPos vStoredOrigin.x -= (vDir.x * fDist) vStoredOrigin.y -= (vDir.y * fDist) GGSM_ENTITY_SET_PACKED_ORIGIN(sGGSMData.sEntities[ind], vStoredOrigin) fDist += fDistBetweenUnits IF (vDir.x < 0) vBasePos.x -= fDistBetweenUnits ELSE vBasePos.x += fDistBetweenUnits ENDIF ENDIF ENDREPEAT ENDPROC PROC GGSM_ENTITY_GROUP_UPDATE_FORMATION_VERTLINE(GGSM_ENTITY_GROUP &group) INT i, ind VECTOR_2D vBasePos = GGSM_FORMATION_GET_START_POSITION(group.sFormSettings) GGSM_ENTITY_TYPE entType = GGSM_FORMATION_GET_ENTITY_TYPE(group.sFormSettings) GGSM_ENTITY_DATA entData = GGSM_ENTITY_DATA_GET(entType) VECTOR_2D spriteSize = GGSM_GET_SPRITE_SIZE(entData.eSpriteType) VECTOR_2D spacing = GGSM_FORMATION_GET_SPACING(group.sFormSettings) FLOAT fDistBetweenUnits = ABSF(spriteSize.y) * spacing.y FLOAT spd = entData.fBaseSpeed vBasePos.y += (TO_FLOAT(group.iMembersToCreate) / 2.0) * fDistBetweenUnits REPEAT group.sFormSettings.iFormationMembers i IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], entType, vBasePos, 0) sGGSMData.sEntities[ind].vLocalDirection = GGSM_FORMATION_GET_START_DIRECTION(group.sFormSettings) sGGSMData.sEntities[ind].fSpeed = spd GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[ind], group.iGroupID) GGSM_ENTITY_CONFIGURE_FROM_FORMATION(sGGSMData.sEntities[ind], group.sFormSettings) vBasePos.y -= fDistBetweenUnits ENDIF ENDREPEAT group.iMembersToCreate = 0 ENDPROC PROC GGSM_ENTITY_GROUP_UPDATE_FORMATION_FLYING_V(GGSM_ENTITY_GROUP &group) INT i, ind GGSM_ENTITY_TYPE entType = GGSM_FORMATION_GET_ENTITY_TYPE(group.sFormSettings) GGSM_ENTITY_DATA entData = GGSM_ENTITY_DATA_GET(entType) VECTOR_2D basePos = GGSM_FORMATION_GET_START_POSITION(group.sFormSettings) VECTOR_2D dir = GGSM_FORMATION_GET_START_DIRECTION(group.sFormSettings) VECTOR_2D spriteSize = GGSM_GET_SPRITE_SIZE(entData.eSpriteType) VECTOR_2D transRootPos, checkPos VECTOR_2D spacing = GGSM_FORMATION_GET_SPACING(group.sFormSettings) // move the group dist counter group.fDistCounter += (entData.fBaseSpeed * GET_FRAME_TIME() * sGGSMData.fTimeScale) transRootPos = basePos GGSM_TRANSLATE_VECTOR_BY_DIRECTION(transRootPos, dir, group.fDistCounter) REPEAT group.sFormSettings.iFormationMembers i IF NOT IS_BIT_SET(group.iFormSpawnBitSet, i) checkPos = GGSM_FORMATION_GET_POSITION_FOR_FLYING_V_EXPLICT(transRootPos, dir, i, spriteSize, spacing) IF GGSM_IS_POINT_ON_SCREEN(checkPos, spriteSize) IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], entType, checkPos, 0) sGGSMData.sEntities[ind].vLocalDirection = dir sGGSMData.sEntities[ind].fSpeed = entData.fBaseSpeed GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[ind], group.iGroupID) GGSM_ENTITY_CONFIGURE_FROM_FORMATION(sGGSMData.sEntities[ind], group.sFormSettings) SET_BIT(group.iFormSpawnBitSet, i) ENDIF ENDIF ENDIF ENDREPEAT ENDPROC PROC GGSM_ENTITY_GROUP_UPDATE_FORMATION_LINE(GGSM_ENTITY_GROUP &group) INT i, ind GGSM_ENTITY_TYPE entType = GGSM_FORMATION_GET_ENTITY_TYPE(group.sFormSettings) GGSM_ENTITY_DATA entData = GGSM_ENTITY_DATA_GET(entType) VECTOR_2D basePos = GGSM_FORMATION_GET_START_POSITION(group.sFormSettings) VECTOR_2D dir = GGSM_FORMATION_GET_START_DIRECTION(group.sFormSettings) VECTOR_2D spriteSize = GGSM_GET_SPRITE_SIZE(entData.eSpriteType) VECTOR_2D transRootPos, checkPos VECTOR_2D spacing = GGSM_FORMATION_GET_SPACING(group.sFormSettings) // move the group dist counter group.fDistCounter += (entData.fBaseSpeed * GET_FRAME_TIME() * sGGSMData.fTimeScale) transRootPos = basePos GGSM_TRANSLATE_VECTOR_BY_DIRECTION(transRootPos, dir, group.fDistCounter) REPEAT group.sFormSettings.iFormationMembers i IF NOT IS_BIT_SET(group.iFormSpawnBitSet, i) checkPos = GGSM_FORMATION_GET_POSITION_FOR_LINE_EXPLICT(transRootPos, dir, i, spriteSize, spacing) IF GGSM_IS_POINT_ON_SCREEN(checkPos, spriteSize) IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], entType, checkPos, 0) sGGSMData.sEntities[ind].vLocalDirection = dir sGGSMData.sEntities[ind].fSpeed = entData.fBaseSpeed GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[ind], group.iGroupID) GGSM_ENTITY_CONFIGURE_FROM_FORMATION(sGGSMData.sEntities[ind], group.sFormSettings) SET_BIT(group.iFormSpawnBitSet, i) ENDIF ENDIF ENDIF ENDREPEAT ENDPROC PROC GGSM_ENTITY_GROUP_UPDATE_FORMATION_MIRROR_X(GGSM_ENTITY_GROUP &group) INT i GGSM_ENTITY_TYPE entType = GGSM_FORMATION_GET_ENTITY_TYPE(group.sFormSettings) GGSM_ENTITY_DATA entData = GGSM_ENTITY_DATA_GET(entType) VECTOR_2D spriteSize = GGSM_GET_SPRITE_SIZE(entData.eSpriteType) FLOAT fDistBetweenUnits = FMAX(ABSF(spriteSize.x), ABSF(spriteSize.y)) * 1.5 FLOAT spd = entData.fBaseSpeed VECTOR_2D dir // move the dist counter so we can ensure the formation is reasonably spaced group.fDistCounter += (spd * GET_FRAME_TIME() * sGGSMData.fTimeScale) group.fDistCounter = CLAMP(group.fDistCounter, 0, fDistBetweenUnits) IF (group.fDistCounter < fDistBetweenUnits) EXIT ENDIF INT ind VECTOR_2D vBasePos // create leader dir = GGSM_FORMATION_GET_START_DIRECTION(group.sFormSettings) REPEAT 2 i IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) vBasePos = GGSM_FORMATION_GET_START_POSITION(group.sFormSettings) IF (i = 1) vBasePos.x = cfBASE_SCREEN_HALF_WIDTH - vBasePos.x vBasePos.x += cfBASE_SCREEN_HALF_WIDTH ENDIF GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], entType, vBasePos, 0) sGGSMData.sEntities[ind].vLocalDirection = dir sGGSMData.sEntities[ind].fSpeed = spd IF (i = 1) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[ind].eMoveFlags, GGSM_MOVE_BIT_FLIP_RELATIVE_PATH_X) ENDIF GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[ind], group.iGroupID) GGSM_ENTITY_CONFIGURE_FROM_FORMATION(sGGSMData.sEntities[ind], group.sFormSettings) ENDIF ENDREPEAT group.fDistCounter = 0 ENDPROC PROC GGSM_ENTITY_GROUP_UPDATE_FORMATION_MIRROR_Y(GGSM_ENTITY_GROUP &group) INT i GGSM_ENTITY_TYPE entType = GGSM_FORMATION_GET_ENTITY_TYPE(group.sFormSettings) GGSM_ENTITY_DATA entData = GGSM_ENTITY_DATA_GET(entType) VECTOR_2D spriteSize = GGSM_GET_SPRITE_SIZE(entData.eSpriteType) FLOAT fDistBetweenUnits = FMAX(ABSF(spriteSize.x), ABSF(spriteSize.y)) * 1.5 FLOAT spd = entData.fBaseSpeed VECTOR_2D dir // move the dist counter so we can ensure the formation is reasonably spaced group.fDistCounter += (spd * GET_FRAME_TIME() * sGGSMData.fTimeScale) group.fDistCounter = CLAMP(group.fDistCounter, 0, fDistBetweenUnits) IF (group.fDistCounter < fDistBetweenUnits) EXIT ENDIF INT ind VECTOR_2D vBasePos // create leader dir = GGSM_FORMATION_GET_START_DIRECTION(group.sFormSettings) REPEAT 2 i IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) vBasePos = GGSM_FORMATION_GET_START_POSITION(group.sFormSettings) IF (i = 1) vBasePos.y = cfBASE_SCREEN_HALF_HEIGHT - vBasePos.y vBasePos.y += cfBASE_SCREEN_HALF_HEIGHT ENDIF GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], entType, vBasePos, 0) sGGSMData.sEntities[ind].vLocalDirection = dir sGGSMData.sEntities[ind].fSpeed = spd IF (i = 1) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[ind].eMoveFlags, GGSM_MOVE_BIT_FLIP_RELATIVE_PATH_Y) ENDIF GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[ind], group.iGroupID) GGSM_ENTITY_CONFIGURE_FROM_FORMATION(sGGSMData.sEntities[ind], group.sFormSettings) ENDIF ENDREPEAT group.fDistCounter = 0 ENDPROC PROC GGSM_ENTITY_GROUP_UPDATE_FORMATION_POWER_UP(GGSM_ENTITY_GROUP &group) GGSM_SPRITE_TYPE eType = GGSM_FORMATION_GET_POWER_UP_SPRITE(group.sFormSettings) IF (eType = GGSM_SPRITE_NONE) group.iMembersToCreate = 0 EXIT ENDIF VECTOR_2D vPos = GGSM_FORMATION_GET_START_POSITION(group.sFormSettings) IF NOT GGSM_CREATE_POWER_UP_AT(eType, vPos, sGGSMData.sPowerUp) EXIT ENDIF GGSM_DEACTIVATE_ENTITY_GROUP(group) group.iMembersToCreate = 0 ENDPROC PROC GGSM_ENTITY_GROUP_UPDATE_FORMATION_BANANA_SNAKE(GGSM_ENTITY_GROUP &group) INT iParent INT iLeader, ind, count, i VECTOR_2D vBasePos = GGSM_FORMATION_GET_START_POSITION(group.sFormSettings) // create leader IF NOT GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) EXIT ENDIF SET_BITMASK_ENUM_AS_ENUM(group.eFlags, GGSM_GROUP_BIT_END_WHEN_ALL_OFFSCREEN | GGSM_GROUP_BIT_DIE_WHEN_LEADER_DIES) GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], GGSM_ENTITY_BANANASLICE_FRONT, vBasePos) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[ind].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[ind].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[ind].eFlags, GGSM_ENTITY_BIT_FORCE_SCROLLING_TO_STOP) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[ind], 0) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[ind], group.iGroupID) GGSM_ENTITY_CONFIGURE_FROM_FORMATION(sGGSMData.sEntities[ind], group.sFormSettings) // create segements iLeader = ind iParent = iLeader count = group.sFormSettings.iFormationMembers - 2 REPEAT count i IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], GGSM_ENTITY_BANANASLICE, INIT_VECTOR_2D(30.0, 0.0), 0, DEFAULT, iParent) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[ind], GGSM_MOVEMENT_SNAKE_SECTION) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[ind], i + 1) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[ind], group.iGroupID) iParent = ind ENDIF ENDREPEAT // create tail IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], GGSM_ENTITY_BANANASLICE_BACK, INIT_VECTOR_2D(30 + 10, 0.0), 0, DEFAULT, iParent) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[ind], GGSM_MOVEMENT_SNAKE_SECTION) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[ind].eMoveFlags, GGSM_MOVE_BIT_ROTATE_TO_FACE_DIRECTION) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[ind], group.sFormSettings.iFormationMembers) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[ind], group.iGroupID) ENDIF group.iMembersToCreate = 0 ENDPROC FUNC BOOL GGSM_ENTITY_GROUP_UPDATE_FORMATION_ARMOURED_FRUITBOWL(GGSM_ENTITY_GROUP &group) INT iLeaderIndex, ind, count, n VECTOR_2D vBasePos = GGSM_FORMATION_GET_START_POSITION(group.sFormSettings) GGSM_FORMATION_TYPE eFormType = GGSM_FORMATION_GET_TYPE(group.sFormSettings) // create leader IF NOT GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, iLeaderIndex, sGGSMData.iEntitySearchIndex) RETURN FALSE ENDIF SET_BITMASK_ENUM_AS_ENUM(group.eFlags, GGSM_GROUP_BIT_ALLOW_OFFSCREEN) SET_BITMASK_ENUM_AS_ENUM(group.eFlags, GGSM_GROUP_BIT_DIE_WHEN_LEADER_DIES) GGSM_ENTITY_INIT(sGGSMData.sEntities[iLeaderIndex], GGSM_ENTITY_ARMOUR_FRUITBOWL, vBasePos) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeaderIndex].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeaderIndex].eFlags, GGSM_ENTITY_BIT_WPN_ACTIVE) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[iLeaderIndex].eFlags, GGSM_ENTITY_BIT_FORCE_SCROLLING_TO_STOP) sGGSMData.sEntities[iLeaderIndex].vLocalDirection = GGSM_FORMATION_GET_START_DIRECTION(group.sFormSettings) GGSM_ENTITY_SET_Z_DEPTH(sGGSMData.sEntities[iLeaderIndex], 0) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[iLeaderIndex], group.iGroupID) GGSM_ENTITY_CONFIGURE_FROM_FORMATION(sGGSMData.sEntities[iLeaderIndex], group.sFormSettings) sGGSMData.sEntities[iLeaderIndex].sLocal.vScale = INIT_VECTOR_2D(1.25, 1.25) FLOAT ang SWITCH (eFormType) CASE GGSM_FORMATION_ARMOUR_FRUITBOWL DEFAULT count = group.sFormSettings.iFormationMembers - 1 IF (count <= 0) RETURN TRUE ENDIF IF (sGGSMData.bHardMode) count += 2 ENDIF ang = 360.0 / TO_FLOAT(count) REPEAT count n IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], GGSM_ENTITY_CIRCLE_SHIP_GREEN, INIT_VECTOR_2D(0, 0), 0, FALSE, iLeaderIndex) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[ind], GGSM_MOVEMENT_ORBIT, 150.0, (n * ang), 1.0) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[ind], GGSM_WEAPON_ENEMYSHOT_RAPID) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[ind].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[ind], group.iGroupID) sGGSMData.sEntities[ind].sLocal.vScale = INIT_VECTOR_2D(0.75, 0.75) sGGSMData.sEntities[ind].iHP = 8 ENDIF ENDREPEAT BREAK CASE GGSM_FORMATION_ARMOUR_FRUITBOWL1 GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[iLeaderIndex], GGSM_WEAPON_ENEMYSPREAD) IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], GGSM_ENTITY_CIRCLE_SHIP_YELLOW, INIT_VECTOR_2D(150, -150), 0, FALSE, iLeaderIndex) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[ind], GGSM_MOVEMENT_NONE) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[ind], GGSM_WEAPON_ENEMYSPREAD) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[ind].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[ind], group.iGroupID) sGGSMData.sEntities[ind].sLocal.vScale = INIT_VECTOR_2D(0.75, 0.75) sGGSMData.sEntities[ind].iHP = 8 ENDIF IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], GGSM_ENTITY_CIRCLE_SHIP_YELLOW, INIT_VECTOR_2D(150, 150), 0, FALSE, iLeaderIndex) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[ind], GGSM_MOVEMENT_NONE) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[ind], GGSM_WEAPON_ENEMYSPREAD) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[ind].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[ind], group.iGroupID) sGGSMData.sEntities[ind].sLocal.vScale = INIT_VECTOR_2D(0.75, 0.75) sGGSMData.sEntities[ind].iHP = 8 ENDIF BREAK CASE GGSM_FORMATION_ARMOUR_FRUITBOWL2 count = group.sFormSettings.iFormationMembers - 1 IF (count <= 0) RETURN TRUE ENDIF REPEAT count n IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], GGSM_ENTITY_CIRCLE_SHIP_GREEN, INIT_VECTOR_2D(0, 0), 0, FALSE, iLeaderIndex) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[ind], GGSM_MOVEMENT_ORBIT, 150.0, (n * ang), 0.5) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[ind], GGSM_WEAPON_ENEMYSHOT) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[ind].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[ind], group.iGroupID) sGGSMData.sEntities[ind].sLocal.vScale = INIT_VECTOR_2D(0.75, 0.75) sGGSMData.sEntities[ind].iHP = 4 ENDIF ENDREPEAT n = 0 REPEAT count n IF GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], GGSM_ENTITY_CIRCLE_SHIP_GREEN, INIT_VECTOR_2D(0, 0), 0, FALSE, iLeaderIndex) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[ind], GGSM_MOVEMENT_ORBIT, 300.0, (n * ang), -0.5) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[ind], GGSM_WEAPON_ENEMYVULCAN) CLEAR_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[ind].eFlags, GGSM_ENTITY_BIT_WPN_TARGETTED) GGSM_ADD_ENTITY_TO_GROUP(sGGSMData.sEntities[ind], group.iGroupID) sGGSMData.sEntities[ind].sLocal.vScale = INIT_VECTOR_2D(0.75, 0.75) sGGSMData.sEntities[ind].iHP = 4 ENDIF ENDREPEAT BREAK ENDSWITCH RETURN TRUE ENDFUNC PROC GGSM_ENTITY_GROUP_UPDATE(GGSM_ENTITY_GROUP &group) IF (group.iMembersToCreate <= 0) EXIT ENDIF INT iBossController IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(group.eFlags, GGSM_GROUP_BIT_ACTIVE) EXIT ENDIF sGGSMData.iGroupsActive ++ IF NOT IS_BITMASK_ENUM_AS_ENUM_SET(group.eFlags, GGSM_GROUP_BIT_IS_FORMATION) EXIT ENDIF IF IS_BITMASK_ENUM_AS_ENUM_SET(group.eFlags, GGSM_GROUP_BIT_IS_PLAYER_GROUP) EXIT ENDIF GGSM_FORMATION_TYPE eType = GGSM_FORMATION_GET_TYPE(group.sFormSettings) SWITCH (eType) CASE GGSM_FORMATION_STANDARD GGSM_ENTITY_GROUP_UPDATE_FORMATION_STANDARD(group) BREAK CASE GGSM_FORMATION_FLYING_V GGSM_ENTITY_GROUP_UPDATE_FORMATION_FLYING_V(group) BREAK CASE GGSM_FORMATION_LINE GGSM_ENTITY_GROUP_UPDATE_FORMATION_LINE(group) BREAK CASE GGSM_FORMATION_MIRROR_X GGSM_ENTITY_GROUP_UPDATE_FORMATION_MIRROR_X(group) BREAK CASE GGSM_FORMATION_MIRROR_Y GGSM_ENTITY_GROUP_UPDATE_FORMATION_MIRROR_Y(group) BREAK CASE GGSM_FORMATION_POWER_UP GGSM_ENTITY_GROUP_UPDATE_FORMATION_POWER_UP(group) BREAK CASE GGSM_FORMATION_HORZLINE GGSM_ENTITY_GROUP_UPDATE_FORMATION_HORZLINE(group) BREAK CASE GGSM_FORMATION_VERTLINE GGSM_ENTITY_GROUP_UPDATE_FORMATION_VERTLINE(group) BREAK CASE GGSM_FORMATION_DELAYED_HLINE GGSM_ENTITY_GROUP_UPDATE_FORMATION_DELAYED_LINE(group, INIT_VECTOR_2D(1, 0)) BREAK CASE GGSM_FORMATION_DELAYED_VLINE GGSM_ENTITY_GROUP_UPDATE_FORMATION_DELAYED_LINE(group, INIT_VECTOR_2D(0, 1)) BREAK CASE GGSM_FORMATION_BANANASNAKE GGSM_ENTITY_GROUP_UPDATE_FORMATION_BANANA_SNAKE(group) BREAK CASE GGSM_FORMATION_ARMOUR_FRUITBOWL CASE GGSM_FORMATION_ARMOUR_FRUITBOWL1 CASE GGSM_FORMATION_ARMOUR_FRUITBOWL2 CASE GGSM_FORMATION_ARMOUR_FRUITBOWL3 CASE GGSM_FORMATION_ARMOUR_FRUITBOWL4 GGSM_ENTITY_GROUP_UPDATE_FORMATION_ARMOURED_FRUITBOWL(group) BREAK CASE GGSM_FORMATION_BOSS_MARINE iBossController = GGSM_GET_FREE_BOSS_CONTROLLER_INDEX(sGGSMData.sBossController) IF (iBossController = GGSM_INVALID_BOSS_CONTROLLER) EXIT ENDIF GGSM_RESET_ENTITY_GROUP(group) GGSM_RESET_BOSS_CONTROLLER(sGGSMData.sBossController[iBossController], GGSM_BOSS_MARINE) BREAK CASE GGSM_FORMATION_BOSS_BREAD iBossController = GGSM_GET_FREE_BOSS_CONTROLLER_INDEX(sGGSMData.sBossController) IF (iBossController = GGSM_INVALID_BOSS_CONTROLLER) EXIT ENDIF GGSM_RESET_ENTITY_GROUP(group) GGSM_RESET_BOSS_CONTROLLER(sGGSMData.sBossController[iBossController], GGSM_BOSS_BREAD) BREAK CASE GGSM_FORMATION_BOSS_SMOOTHIE iBossController = GGSM_GET_FREE_BOSS_CONTROLLER_INDEX(sGGSMData.sBossController) IF (iBossController = GGSM_INVALID_BOSS_CONTROLLER) EXIT ENDIF GGSM_RESET_ENTITY_GROUP(group) GGSM_RESET_BOSS_CONTROLLER(sGGSMData.sBossController[iBossController], GGSM_BOSS_SMOOTHIE) BREAK CASE GGSM_FORMATION_BOSS_DR_DANK iBossController = GGSM_GET_FREE_BOSS_CONTROLLER_INDEX(sGGSMData.sBossController) IF (iBossController = GGSM_INVALID_BOSS_CONTROLLER) EXIT ENDIF GGSM_RESET_ENTITY_GROUP(group) GGSM_RESET_BOSS_CONTROLLER(sGGSMData.sBossController[iBossController], GGSM_BOSS_DR_DANK) BREAK CASE GGSM_FORMATION_BOSS_GRANANA iBossController = GGSM_GET_FREE_BOSS_CONTROLLER_INDEX(sGGSMData.sBossController) IF (iBossController = GGSM_INVALID_BOSS_CONTROLLER) EXIT ENDIF GGSM_RESET_ENTITY_GROUP(group) GGSM_RESET_BOSS_CONTROLLER(sGGSMData.sBossController[iBossController], GGSM_BOSS_GRANANA) BREAK ENDSWITCH ENDPROC //------------------------------------------------- // SPECIAL INIT FUNCTIONS //------------------------------------------------- FUNC BOOL GGSM_PLAYER_SHIP_INIT(VECTOR_2D vLocalPos) INT ind IF NOT GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) RETURN FALSE ENDIF GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], GGSM_ENTITY_PLAYERSHIP, vLocalPos, DEFAULT, TRUE) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[ind], GGSM_MOVEMENT_PLAYER_CONTROLLED) //GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[ind], GGSM_WEAPON_PLYRBACKVULCAN) sGGSMData.iPlayerShipIndex = ind sGGSMData.fKillStreakTimer = 0.0 sGGSMData.iKillStreak = 0 sGGSMData.bGrazed = FALSE RETURN TRUE ENDFUNC FUNC BOOL GGSM_PLAYER_DECOY_INIT(VECTOR_2D vLocalPos) INT ind IF NOT GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) RETURN FALSE ENDIF GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], GGSM_ENTITY_PLAYERDECOY, vLocalPos, DEFAULT, TRUE) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[ind], GGSM_WEAPON_NONE) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[ind], GGSM_MOVEMENT_NONE) sGGSMData.sEntities[ind].iPackedColor = GGSM_PACK_RGBA_COLOUR(0, 255, 0, 128) sGGSMData.iPlayerDecoyIndex = ind RETURN TRUE ENDFUNC FUNC BOOL GGSM_PLAYER_SHIELD_INIT(BOOL bReflectShield = FALSE) INT ind IF GGSM_DOES_PLAYER_SHIELD_EXIST() GGSM_ENTITY_DESTROY(sGGSMData.sEntities[sGGSMData.iPlayerShieldIndex]) ENDIF IF NOT GGSM_GET_FREE_ENTITY(sGGSMData.sEntities, ind, sGGSMData.iEntitySearchIndex) RETURN FALSE ENDIF GGSM_ENTITY_INIT(sGGSMData.sEntities[ind], GGSM_ENTITY_PLAYERSHIELD, INIT_VECTOR_2D(0, 0), DEFAULT, TRUE, sGGSMData.iPlayerShipIndex) GGSM_ENTITY_SET_WEAPON(sGGSMData.sEntities[ind], GGSM_WEAPON_NONE) GGSM_ENTITY_SET_MOVEMENT_TYPE(sGGSMData.sEntities[ind], GGSM_MOVEMENT_NONE) IF (bReflectShield) SET_BITMASK_ENUM_AS_ENUM(sGGSMData.sEntities[ind].eFlags, GGSM_ENTITY_BIT_REFLECT_BULLETS) sGGSMData.sEntities[ind].iPackedColor = GGSM_PACK_RGBA_COLOUR(0, 255, 0, 255) ELSE sGGSMData.sEntities[ind].iPackedColor = GGSM_PACK_RGBA_COLOUR(0, 0, 255, 255) ENDIF sGGSMData.iPlayerShieldIndex = ind RETURN TRUE ENDFUNC FUNC FLOAT GGSM_GET_PLAYER_SHIP_HP_PERCENTAGE() IF NOT GGSM_DOES_PLAYER_SHIP_EXIST() RETURN 0.0 ENDIF GGSM_ENTITY_DATA dat = GGSM_ENTITY_DATA_GET(sGGSMData.sEntities[sGGSMData.iPlayerShipIndex].eType) RETURN TO_FLOAT(sGGSMData.sEntities[sGGSMData.iPlayerShipIndex].iHP) / TO_FLOAT(dat.iMaxHP) ENDFUNC