static bool TryPlacePickup(HealthPickups *h) { Vec2i size = Vec2iNew(HEALTH_W, HEALTH_H); // Attempt to place one in unexplored area for (int i = 0; i < 100; i++) { const Vec2i v = MapGenerateFreePosition(h->map, size); if (!Vec2iIsZero(v) && !MapGetTile(h->map, Vec2iToTile(v))->isVisited) { MapPlaceHealth(v); return true; } } // Attempt to place one in out-of-sight area for (int i = 0; i < 100; i++) { const Vec2i v = MapGenerateFreePosition(h->map, size); const Vec2i fullpos = Vec2iReal2Full(v); const TActor *closestPlayer = AIGetClosestPlayer(fullpos); if (!Vec2iIsZero(v) && (!closestPlayer || CHEBYSHEV_DISTANCE( fullpos.x, fullpos.y, closestPlayer->Pos.x, closestPlayer->Pos.y) >= 256 * 150)) { MapPlaceHealth(v); return true; } } // Attempt to place one anyway for (int i = 0; i < 100; i++) { const Vec2i v = MapGenerateFreePosition(h->map, size); if (!Vec2iIsZero(v)) { MapPlaceHealth(v); return true; } } return false; }
static void HandleGameEvent( GameEvent *e, HUD *hud, ScreenShake *shake, HealthPickups *hp, EventHandlers *eventHandlers) { switch (e->Type) { case GAME_EVENT_SCORE: Score(&gPlayerDatas[e->u.Score.PlayerIndex], e->u.Score.Score); HUDAddScoreUpdate(hud, e->u.Score.PlayerIndex, e->u.Score.Score); break; case GAME_EVENT_SOUND_AT: if (e->u.SoundAt.Sound) { SoundPlayAt( &gSoundDevice, e->u.SoundAt.Sound, e->u.SoundAt.Pos); } break; case GAME_EVENT_SCREEN_SHAKE: *shake = ScreenShakeAdd( *shake, e->u.ShakeAmount, gConfig.Graphics.ShakeMultiplier); break; case GAME_EVENT_SET_MESSAGE: HUDDisplayMessage( hud, e->u.SetMessage.Message, e->u.SetMessage.Ticks); break; case GAME_EVENT_GAME_START: if (eventHandlers->netInput.channel.state == CHANNEL_STATE_CONNECTED) { NetInputSendMsg( &eventHandlers->netInput, SERVER_MSG_GAME_START); } break; case GAME_EVENT_ADD_HEALTH_PICKUP: MapPlaceHealth(e->u.AddPos); break; case GAME_EVENT_TAKE_HEALTH_PICKUP: if (IsPlayerAlive(e->u.PickupPlayer)) { TActor *player = CArrayGet( &gActors, gPlayerIds[e->u.PickupPlayer]); ActorHeal(player, HEALTH_PICKUP_HEAL_AMOUNT); HealthPickupsRemoveOne(hp); HUDAddHealthUpdate( hud, e->u.PickupPlayer, HEALTH_PICKUP_HEAL_AMOUNT); } break; case GAME_EVENT_MOBILE_OBJECT_REMOVE: MobObjDestroy(e->u.MobileObjectRemoveId); break; case GAME_EVENT_ADD_BULLET: BulletAdd( e->u.AddBullet.Bullet, e->u.AddBullet.MuzzlePos, e->u.AddBullet.MuzzleHeight, e->u.AddBullet.Angle, e->u.AddBullet.Direction, e->u.AddBullet.Flags, e->u.AddBullet.PlayerIndex); break; case GAME_EVENT_ADD_MUZZLE_FLASH: AddMuzzleFlash( e->u.AddMuzzleFlash.FullPos, e->u.AddMuzzleFlash.MuzzleHeight, e->u.AddMuzzleFlash.Sprites, e->u.AddMuzzleFlash.Direction, e->u.AddMuzzleFlash.Color, e->u.AddMuzzleFlash.Duration); break; case GAME_EVENT_ADD_FIREBALL: AddFireball(e->u.AddFireball); break; case GAME_EVENT_HIT_CHARACTER: HitCharacter( e->u.HitCharacter.Flags, e->u.HitCharacter.PlayerIndex, CArrayGet(&gActors, e->u.HitCharacter.TargetId), e->u.HitCharacter.Special, e->u.HitCharacter.HasHitSound); break; case GAME_EVENT_ACTOR_IMPULSE: { TActor *a = CArrayGet(&gActors, e->u.ActorImpulse.Id); a->Vel = Vec2iAdd(a->Vel, e->u.ActorImpulse.Vel); } break; case GAME_EVENT_DAMAGE_CHARACTER: DamageCharacter( e->u.DamageCharacter.Power, e->u.DamageCharacter.PlayerIndex, CArrayGet(&gActors, e->u.DamageCharacter.TargetId)); if (e->u.DamageCharacter.Power != 0) { HUDAddHealthUpdate( hud, e->u.DamageCharacter.TargetPlayerIndex, -e->u.DamageCharacter.Power); } break; case GAME_EVENT_TRIGGER: { const Tile *t = MapGetTile(&gMap, e->u.Trigger.TilePos); for (int i = 0; i < (int)t->triggers.size; i++) { Trigger **tp = CArrayGet(&t->triggers, i); if ((*tp)->id == e->u.Trigger.Id) { TriggerActivate(*tp, &gMap.triggers); break; } } } break; case GAME_EVENT_UPDATE_OBJECTIVE: { struct Objective *o = CArrayGet( &gMission.Objectives, e->u.UpdateObjective.ObjectiveIndex); o->done += e->u.UpdateObjective.Update; MissionObjective *mo = CArrayGet( &gMission.missionData->Objectives, e->u.UpdateObjective.ObjectiveIndex); switch (mo->Type) { case OBJECTIVE_COLLECT: { GameEvent e1; e1.Type = GAME_EVENT_SCORE; e1.u.Score.PlayerIndex = e->u.UpdateObjective.PlayerIndex; e1.u.Score.Score = PICKUP_SCORE; HandleGameEvent(&e1, hud, shake, hp, eventHandlers); } break; case OBJECTIVE_DESTROY: { GameEvent e1; e1.Type = GAME_EVENT_SCORE; e1.u.Score.PlayerIndex = e->u.UpdateObjective.PlayerIndex; e1.u.Score.Score = OBJECT_SCORE; HandleGameEvent(&e1, hud, shake, hp, eventHandlers); } break; default: // No other special objective handling break; } // Display a text update effect for the objective HUDAddObjectiveUpdate( hud, e->u.UpdateObjective.ObjectiveIndex, e->u.UpdateObjective.Update); MissionSetMessageIfComplete(&gMission); } break; case GAME_EVENT_MISSION_COMPLETE: HUDDisplayMessage(hud, "Mission complete", -1); hud->showExit = true; MapShowExitArea(&gMap); break; case GAME_EVENT_MISSION_INCOMPLETE: gMission.state = MISSION_STATE_PLAY; break; case GAME_EVENT_MISSION_PICKUP: gMission.state = MISSION_STATE_PICKUP; gMission.pickupTime = gMission.time; SoundPlay(&gSoundDevice, StrSound("whistle")); break; case GAME_EVENT_MISSION_END: gMission.isDone = true; break; default: assert(0 && "unknown game event"); break; } }