diff --git a/src/cdogs/actors.c b/src/cdogs/actors.c
index 61d95c1aa..9da0aa0f9 100644
--- a/src/cdogs/actors.c
+++ b/src/cdogs/actors.c
@@ -1001,9 +1001,8 @@ static bool ActorTryChangeDirection(
 {
 	const bool willChangeDirecton =
 		!actor->petrified && CMD_HAS_DIRECTION(cmd) &&
-		(!Button2(cmd) ||
-		 ConfigGetEnum(&gConfig, "Game.SwitchMoveStyle") !=
-			 SWITCHMOVE_STRAFE) &&
+		(!Button2(cmd) || ConfigGetEnum(&gConfig, "Game.SwitchMoveStyle") !=
+							  SWITCHMOVE_STRAFE) &&
 		(!Button1(prevCmd) ||
 		 ConfigGetEnum(&gConfig, "Game.FireMoveStyle") != FIREMOVE_STRAFE);
 	const direction_e dir = CmdToDirection(cmd);
@@ -1128,13 +1127,13 @@ void CommandActor(TActor *actor, int cmd, int ticks)
 static bool ActorTryMove(TActor *actor, int cmd, int ticks)
 {
 	const bool canMoveWhenShooting =
-	actor->PlayerUID < 0 ? (actor->flags & FLAGS_MOVE_AND_SHOOT) :
-	(
-	 ConfigGetEnum(&gConfig, "Game.FireMoveStyle") != FIREMOVE_STOP ||
-		(ConfigGetEnum(&gConfig, "Game.SwitchMoveStyle") ==
-			 SWITCHMOVE_STRAFE &&
-		 Button2(cmd))
-	 );
+		actor->PlayerUID < 0
+			? (actor->flags & FLAGS_MOVE_AND_SHOOT)
+			: (ConfigGetEnum(&gConfig, "Game.FireMoveStyle") !=
+				   FIREMOVE_STOP ||
+			   (ConfigGetEnum(&gConfig, "Game.SwitchMoveStyle") ==
+					SWITCHMOVE_STRAFE &&
+				Button2(cmd)));
 	const bool canMove = !actor->hasShot || canMoveWhenShooting;
 	const bool willMove =
 		!actor->petrified && CMD_HAS_DIRECTION(cmd) && canMove;
@@ -1479,7 +1478,7 @@ static void ActorDie(TActor *actor)
 	GameEvent e = GameEventNew(GAME_EVENT_ACTOR_DIE);
 	e.u.ActorDie.UID = actor->uid;
 	GameEventsEnqueue(&gGameEvents, e);
-	
+
 	// Persist player ammo for when they respawn
 	ActorPersistPlayerWeaponsAndAmmo(actor);
 }
@@ -1701,10 +1700,10 @@ TActor *ActorAdd(NActorAdd aa)
 		{
 			// Use persisted ammo amount if it is greater,
 			// or if buy/sell is enabled
-			if (gCampaign.Setting.BuyAndSell ||
-				(int)aa.Ammo[i].Amount >
-					AmmoGetById(&gAmmo, aa.Ammo[i].Id)->Amount *
-						AMMO_STARTING_MULTIPLE)
+			const Ammo *ammo = AmmoGetById(&gAmmo, aa.Ammo[i].Id);
+			if (ammo && (gCampaign.Setting.BuyAndSell ||
+						 (int)aa.Ammo[i].Amount >
+							 ammo->Amount * AMMO_STARTING_MULTIPLE))
 			{
 				CArraySet(&actor->ammo, aa.Ammo[i].Id, &aa.Ammo[i].Amount);
 			}
diff --git a/src/cdogs/ammo.c b/src/cdogs/ammo.c
index b3859e3b4..d71ff9b5f 100644
--- a/src/cdogs/ammo.c
+++ b/src/cdogs/ammo.c
@@ -1,29 +1,29 @@
 /*
-    C-Dogs SDL
-    A port of the legendary (and fun) action/arcade cdogs.
-    Copyright (c) 2014, 2016-2019, 2023 Cong Xu
-    All rights reserved.
-
-    Redistribution and use in source and binary forms, with or without
-    modification, are permitted provided that the following conditions are met:
-
-    Redistributions of source code must retain the above copyright notice, this
-    list of conditions and the following disclaimer.
-    Redistributions in binary form must reproduce the above copyright notice,
-    this list of conditions and the following disclaimer in the documentation
-    and/or other materials provided with the distribution.
-
-    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-    POSSIBILITY OF SUCH DAMAGE.
+	C-Dogs SDL
+	A port of the legendary (and fun) action/arcade cdogs.
+	Copyright (c) 2014, 2016-2019, 2023-2024 Cong Xu
+	All rights reserved.
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions are met:
+
+	Redistributions of source code must retain the above copyright notice, this
+	list of conditions and the following disclaimer.
+	Redistributions in binary form must reproduce the above copyright notice,
+	this list of conditions and the following disclaimer in the documentation
+	and/or other materials provided with the distribution.
+
+	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+	POSSIBILITY OF SUCH DAMAGE.
 */
 #include "ammo.h"
 
@@ -34,10 +34,8 @@
 #include "pic_manager.h"
 #include "utils.h"
 
-
 AmmoClasses gAmmo;
 
-
 // TODO: use map structure?
 Ammo *StrAmmo(const char *s)
 {
@@ -50,16 +48,16 @@ int StrAmmoId(const char *s)
 		return 0;
 	}
 	CA_FOREACH(Ammo, a, gAmmo.CustomAmmo)
-		if (strcmp(s, a->Name) == 0)
-		{
-			return _ca_index + (int)gAmmo.Ammo.size;
-		}
+	if (strcmp(s, a->Name) == 0)
+	{
+		return _ca_index + (int)gAmmo.Ammo.size;
+	}
 	CA_FOREACH_END()
 	CA_FOREACH(Ammo, a, gAmmo.Ammo)
-		if (strcmp(s, a->Name) == 0)
-		{
-			return _ca_index;
-		}
+	if (strcmp(s, a->Name) == 0)
+	{
+		return _ca_index;
+	}
 	CA_FOREACH_END()
 	CASSERT(false, "cannot parse ammo name");
 	return 0;
@@ -87,8 +85,8 @@ void AmmoInitialize(AmmoClasses *ammo, const char *path)
 	e = json_stream_parse(f, &root);
 	if (e != JSON_OK)
 	{
-		LOG(LM_MAIN, LL_ERROR, "Error parsing ammo file %s [error %d]",
-			buf, (int)e);
+		LOG(LM_MAIN, LL_ERROR, "Error parsing ammo file %s [error %d]", buf,
+			(int)e);
 		goto bail;
 	}
 	AmmoLoadJSON(&ammo->Ammo, root);
@@ -139,9 +137,9 @@ static void LoadAmmo(Ammo *a, json_t *node, const int version)
 void AmmoClassesClear(CArray *ammo)
 {
 	CA_FOREACH(Ammo, a, *ammo)
-		CFREE(a->Name);
-		CFREE(a->Sound);
-		CFREE(a->DefaultGun);
+	CFREE(a->Name);
+	CFREE(a->Sound);
+	CFREE(a->DefaultGun);
 	CA_FOREACH_END()
 	CArrayClear(ammo);
 }
@@ -159,10 +157,12 @@ Ammo *AmmoGetById(AmmoClasses *ammo, const int id)
 	{
 		return CArrayGet(&ammo->Ammo, id);
 	}
-	else
+	const int id2 = id - (int)ammo->Ammo.size;
+	if (id < (int)ammo->CustomAmmo.size)
 	{
-		return CArrayGet(&ammo->CustomAmmo, id - (int)ammo->Ammo.size);
+		return CArrayGet(&ammo->CustomAmmo, id2);
 	}
+	return NULL;
 }
 
 int AmmoGetNumClasses(const AmmoClasses *ammo)
@@ -170,7 +170,6 @@ int AmmoGetNumClasses(const AmmoClasses *ammo)
 	return (int)ammo->Ammo.size + (int)ammo->CustomAmmo.size;
 }
 
-
 bool AmmoIsLow(const Ammo *a, const int amount)
 {
 	// Low ammo if less than or equal to half the default amount
diff --git a/src/cdogs/map_build.c b/src/cdogs/map_build.c
index d32ac2884..e32fe0f15 100644
--- a/src/cdogs/map_build.c
+++ b/src/cdogs/map_build.c
@@ -22,7 +22,7 @@
 	This file incorporates work covered by the following copyright and
 	permission notice:
 
-	Copyright (c) 2013-2014, 2017-2023 Cong Xu
+	Copyright (c) 2013-2014, 2017-2024 Cong Xu
 	All rights reserved.
 
 	Redistribution and use in source and binary forms, with or without
@@ -69,7 +69,9 @@ static void MapSetupDoors(MapBuilder *mb);
 static void MapAddDrains(MapBuilder *mb);
 static void MapGenerateRandomExitArea(Map *map, const int mission);
 void MapBuild(
-	Map *m, const Mission *mission, const bool loadDynamic, const int missionIndex, const GameMode mode, const CharacterStore *characters)
+	Map *m, const Mission *mission, const bool loadDynamic,
+	const int missionIndex, const GameMode mode,
+	const CharacterStore *characters)
 {
 	MapBuilder mb;
 	MapBuilderInit(&mb, m, mission, mode, characters);
@@ -188,14 +190,16 @@ static void MapSetupDoors(MapBuilder *mb)
 {
 	// Mark doors as set up as we go
 	CArray doorsSetup;
-	CArrayInitFillZero(&doorsSetup, sizeof(bool), mb->Map->Size.x * mb->Map->Size.y);
-	
+	CArrayInitFillZero(
+		&doorsSetup, sizeof(bool), mb->Map->Size.x * mb->Map->Size.y);
+
 	RECT_FOREACH(Rect2iNew(svec2i_zero(), mb->Map->Size))
 	// Check if this door tile hasn't been set up yet
 	const int idx = _v.x + _v.y * mb->Map->Size.x;
 	if (MapBuilderIsDoor(mb, _v) && !*(bool *)CArrayGet(&doorsSetup, idx))
 	{
-		const struct vec2i groupSize = MapAddDoorGroup(mb, _v, MapGetAccessFlags(mb, _v));
+		const struct vec2i groupSize =
+			MapAddDoorGroup(mb, _v, MapGetAccessFlags(mb, _v));
 		for (int dx = 0; dx < groupSize.x; dx++)
 		{
 			for (int dy = 0; dy < groupSize.y; dy++)
@@ -206,7 +210,7 @@ static void MapSetupDoors(MapBuilder *mb)
 		}
 	}
 	RECT_FOREACH_END()
-	
+
 	CArrayTerminate(&doorsSetup);
 }
 static bool MapBuilderIsDoor(const MapBuilder *mb, const struct vec2i v)
@@ -230,7 +234,8 @@ static int MapGetAccessFlags(const MapBuilder *mb, const struct vec2i v)
 }
 
 void MapBuilderInit(
-	MapBuilder *mb, Map *m, const Mission *mission, const GameMode mode, const CharacterStore *characters)
+	MapBuilder *mb, Map *m, const Mission *mission, const GameMode mode,
+	const CharacterStore *characters)
 {
 	memset(mb, 0, sizeof *mb);
 	mb->Map = m;
@@ -440,7 +445,7 @@ void MapLoadDynamic(MapBuilder *mb)
 		MapTryPlaceOneObject(mb, MapGetRandomTile(mb->Map), mod->M, 0, true);
 	}
 	CA_FOREACH_END()
-	
+
 	CA_FOREACH(const PickupCount, pc, mb->mission->PickupCounts)
 	for (int j = 0; j < pc->Count; j++)
 	{
@@ -467,7 +472,8 @@ void MapLoadDynamic(MapBuilder *mb)
 		AddKeys(mb);
 	}
 }
-static bool MapTryPlaceBlowup(MapBuilder *mb, const int objective, const bool strict);
+static bool MapTryPlaceBlowup(
+	MapBuilder *mb, const int objective, const bool strict);
 static int MapTryPlaceCollectible(MapBuilder *mb, const int objective);
 static void AddObjectives(MapBuilder *mb)
 {
@@ -583,7 +589,8 @@ typedef struct
 } TryPlaceOneBlowupData;
 static bool TryPlaceOneBlowup(
 	MapBuilder *mb, const struct vec2i tilePos, void *data);
-static bool MapTryPlaceBlowup(MapBuilder *mb, const int objective, const bool strict)
+static bool MapTryPlaceBlowup(
+	MapBuilder *mb, const int objective, const bool strict)
 {
 	TryPlaceOneBlowupData data;
 	data.o = CArrayGet(&mb->mission->Objectives, objective);
@@ -597,7 +604,8 @@ static bool TryPlaceOneBlowup(
 	MapBuilder *mb, const struct vec2i tilePos, void *data)
 {
 	const TryPlaceOneBlowupData *pData = data;
-	return MapTryPlaceDestroyObject(mb, mb->mission, pData->objective, tilePos, pData->strict);
+	return MapTryPlaceDestroyObject(
+		mb, mb->mission, pData->objective, tilePos, pData->strict);
 }
 
 void MapBuilderSetLeaveFree(
@@ -657,7 +665,8 @@ static void MapSetupTilesAndWalls(MapBuilder *mb)
 	MapSetupTile(mb, _v);
 	RECT_FOREACH_END()
 
-	if (mb->mission->Type != MAPTYPE_STATIC || mb->mission->u.Static.AltFloorsEnabled)
+	if (mb->mission->Type != MAPTYPE_STATIC ||
+		mb->mission->u.Static.AltFloorsEnabled)
 	{
 		// Randomly change normal floor tiles to alternative floor tiles
 		for (int i = 0; i < mb->Map->Size.x * mb->Map->Size.y / 22; i++)
@@ -667,9 +676,8 @@ static void MapSetupTilesAndWalls(MapBuilder *mb)
 			{
 				Tile *t = MapGetTile(mb->Map, pos);
 				t->Class = TileClassesGetMaskedTile(
-					mb->Map->TileClasses,
-					t->Class, t->Class->Style, "alt1", t->Class->Mask,
-					t->Class->MaskAlt);
+					mb->Map->TileClasses, t->Class, t->Class->Style, "alt1",
+					t->Class->Mask, t->Class->MaskAlt);
 			}
 		}
 		for (int i = 0; i < mb->Map->Size.x * mb->Map->Size.y / 16; i++)
@@ -679,9 +687,8 @@ static void MapSetupTilesAndWalls(MapBuilder *mb)
 			{
 				Tile *t = MapGetTile(mb->Map, pos);
 				t->Class = TileClassesGetMaskedTile(
-					mb->Map->TileClasses,
-					t->Class, t->Class->Style, "alt2", t->Class->Mask,
-					t->Class->MaskAlt);
+					mb->Map->TileClasses, t->Class, t->Class->Style, "alt2",
+					t->Class->Mask, t->Class->MaskAlt);
 			}
 		}
 	}
@@ -703,21 +710,20 @@ static void MapSetupTile(MapBuilder *mb, const struct vec2i pos)
 	if (tc->Type == TILE_CLASS_FLOOR)
 	{
 		t->Class = TileClassesGetMaskedTile(
-			mb->Map->TileClasses,
-			tc, tc->Style, canSeeTileAbove ? "normal" : "shadow", tc->Mask,
-			tc->MaskAlt);
+			mb->Map->TileClasses, tc, tc->Style,
+			canSeeTileAbove ? "normal" : "shadow", tc->Mask, tc->MaskAlt);
 	}
 	else if (tc->Type == TILE_CLASS_WALL)
 	{
 		t->Class = TileClassesGetMaskedTile(
-			mb->Map->TileClasses,
-			tc, tc->Style, MapGetWallPic(mb, pos), tc->Mask, tc->MaskAlt);
+			mb->Map->TileClasses, tc, tc->Style, MapGetWallPic(mb, pos),
+			tc->Mask, tc->MaskAlt);
 	}
 	else if (tc->Type == TILE_CLASS_DOOR)
 	{
 		t->Class = TileClassesGetMaskedTile(
-			mb->Map->TileClasses,
-			tc, tc->Style, "normal_h", tc->Mask, tc->MaskAlt);
+			mb->Map->TileClasses, tc, tc->Style, "normal_h", tc->Mask,
+			tc->MaskAlt);
 	}
 	else if (tc->Type == TILE_CLASS_NOTHING)
 	{
@@ -899,12 +905,14 @@ static bool MapBuilderGetIsRoom(const MapBuilder *mb, const struct vec2i pos)
 }
 
 void MapMakeRoomWalls(
-	MapBuilder *mb, const RoomParams r, const TileClass *wall, const Rect2i room)
+	MapBuilder *mb, const RoomParams r, const TileClass *wall,
+	const Rect2i room)
 {
 	int count = 0;
 	for (int i = 0; i < 100 && count < r.Walls; i++)
 	{
-		if (!MapTryBuildWall(mb, true, MAX(r.WallPad, 1), r.WallLength, wall, room))
+		if (!MapTryBuildWall(
+				mb, true, MAX(r.WallPad, 1), r.WallLength, wall, room))
 		{
 			continue;
 		}
@@ -920,9 +928,9 @@ bool MapTryBuildWall(
 	const TileClass *wall, const Rect2i r)
 {
 	const struct vec2i v =
-		Rect2iIsZero(r) ?
-		MapGetRandomTile(mb->Map) :
-		svec2i_add(r.Pos, svec2i(rand() % r.Size.x, rand() % r.Size.y));
+		Rect2iIsZero(r)
+			? MapGetRandomTile(mb->Map)
+			: svec2i_add(r.Pos, svec2i(rand() % r.Size.x, rand() % r.Size.y));
 	if (MapIsValidStartForWall(mb, v, isRoom, pad))
 	{
 		MapBuilderSetTile(mb, v, wall);
@@ -1090,11 +1098,14 @@ static void AddOverlapRooms(
 	CA_FOREACH_END()
 }
 
-static void PlaceDoors(MapBuilder *mb, const int doorSize, const int roomDim, const struct vec2i doorStart, const struct vec2i d, const bool randomPos, const TileClass *tile);
+static void PlaceDoors(
+	MapBuilder *mb, const int doorSize, const int roomDim,
+	const struct vec2i doorStart, const struct vec2i d, const bool randomPos,
+	const TileClass *tile);
 void MapPlaceDoors(
 	MapBuilder *mb, const Rect2i r, const bool hasDoors, const bool doors[4],
-	const int doorMin, const int doorMax, const uint16_t accessMask, const bool randomPos,
-	const TileClass *door, const TileClass *floor)
+	const int doorMin, const int doorMax, const uint16_t accessMask,
+	const bool randomPos, const TileClass *door, const TileClass *floor)
 {
 	const TileClass *tile = hasDoors ? door : floor;
 
@@ -1107,39 +1118,40 @@ void MapPlaceDoors(
 		{
 			continue;
 		}
-		const int doorSize = doorMax > doorMin ? RAND_INT(doorMin, doorMax) : doorMin;
+		const int doorSize =
+			doorMax > doorMin ? RAND_INT(doorMin, doorMax) : doorMin;
 		int roomDim;
 		struct vec2i d;
 		struct vec2i doorStart;
 		switch (i)
 		{
-			case 0:
-				// left
-				roomDim = r.Size.y;
-				d = svec2i(1, 0);
-				doorStart = r.Pos;
-				break;
-			case 1:
-				// right
-				roomDim = r.Size.y;
-				d = svec2i(1, 0);
-				doorStart = svec2i(r.Pos.x + r.Size.x - 1, r.Pos.y);
-				break;
-			case 2:
-				// top
-				roomDim = r.Size.x;
-				d = svec2i(0, 1);
-				doorStart = r.Pos;
-				break;
-			case 3:
-				// bottom:
-				roomDim = r.Size.x;
-				d = svec2i(0, 1);
-				doorStart = svec2i(r.Pos.x, r.Pos.y + r.Size.y - 1);
-				break;
-			default:
-				CASSERT(false, "unexpected side index");
-				return;
+		case 0:
+			// left
+			roomDim = r.Size.y;
+			d = svec2i(1, 0);
+			doorStart = r.Pos;
+			break;
+		case 1:
+			// right
+			roomDim = r.Size.y;
+			d = svec2i(1, 0);
+			doorStart = svec2i(r.Pos.x + r.Size.x - 1, r.Pos.y);
+			break;
+		case 2:
+			// top
+			roomDim = r.Size.x;
+			d = svec2i(0, 1);
+			doorStart = r.Pos;
+			break;
+		case 3:
+			// bottom:
+			roomDim = r.Size.x;
+			d = svec2i(0, 1);
+			doorStart = svec2i(r.Pos.x, r.Pos.y + r.Size.y - 1);
+			break;
+		default:
+			CASSERT(false, "unexpected side index");
+			return;
 		}
 		PlaceDoors(mb, doorSize, roomDim, doorStart, d, randomPos, tile);
 	}
@@ -1147,22 +1159,29 @@ void MapPlaceDoors(
 static bool TryPlaceDoorTile(
 	MapBuilder *mb, const struct vec2i v, const struct vec2i d,
 	const TileClass *tile);
-static void PlaceDoors(MapBuilder *mb, const int doorSize, const int roomDim, const struct vec2i doorStart, const struct vec2i d, const bool randomPos, const TileClass *tile)
+static void PlaceDoors(
+	MapBuilder *mb, const int doorSize, const int roomDim,
+	const struct vec2i doorStart, const struct vec2i d, const bool randomPos,
+	const TileClass *tile)
 {
 	const struct vec2i dAcross = svec2i_subtract(svec2i_one(), d);
 	const int size = MIN(doorSize, roomDim - 2);
 	struct vec2i start = doorStart;
 	if (randomPos)
 	{
-		start = svec2i_add(start, svec2i_scale(dAcross, (float)RAND_INT(1, roomDim - size - 1)));
+		start = svec2i_add(
+			start,
+			svec2i_scale(dAcross, (float)RAND_INT(1, roomDim - size - 1)));
 	}
 	else
 	{
-		start = svec2i_add(start, svec2i_scale(dAcross, (float)((roomDim - size) / 2)));
+		start = svec2i_add(
+			start, svec2i_scale(dAcross, (float)((roomDim - size) / 2)));
 	}
 	for (int i = 0; i < size; i++)
 	{
-		const struct vec2i v = svec2i_add(start, svec2i_scale(dAcross, (float)i));
+		const struct vec2i v =
+			svec2i_add(start, svec2i_scale(dAcross, (float)i));
 		if (!TryPlaceDoorTile(mb, v, d, tile))
 		{
 			break;
@@ -1437,7 +1456,9 @@ bool MapIsLessThanTwoWallOverlaps(
 	return true;
 }
 
-void MapFillRect(MapBuilder *mb, const Rect2i r, const TileClass *edge, const TileClass *fill)
+void MapFillRect(
+	MapBuilder *mb, const Rect2i r, const TileClass *edge,
+	const TileClass *fill)
 {
 	RECT_FOREACH(r)
 	const TileClass *tc = Rect2iIsAtEdge(r, _v) ? edge : fill;
@@ -1509,10 +1530,10 @@ static void MapGenerateRandomExitArea(Map *map, const int mission)
 	exit.Hidden = false;
 	for (int i = 0; i < 10000 && (t == NULL || !TileCanWalk(t)); i++)
 	{
-		exit.R.Pos.x = (rand() % (abs(map->Size.x) - EXIT_WIDTH - 1));
-		exit.R.Size.x = EXIT_WIDTH + 1;
-		exit.R.Pos.y = (rand() % (abs(map->Size.y) - EXIT_HEIGHT - 1));
-		exit.R.Size.y = EXIT_HEIGHT + 1;
+		exit.R.Size.x = MIN(map->Size.x - 2, EXIT_WIDTH + 1);
+		exit.R.Pos.x = (rand() % (abs(map->Size.x) - exit.R.Size.x));
+		exit.R.Size.y = MIN(map->Size.y - 2, EXIT_HEIGHT + 1);
+		exit.R.Pos.y = (rand() % (abs(map->Size.y) - exit.R.Size.y));
 		// Check that the exit area is walkable
 		t = MapGetTile(map, Rect2iCenter(exit.R));
 	}