This file is an essay about level changing mechanisms. At the time of this writing, Zorn has only a single level. In fact, it *consists* of only a single level, whose lifetime is equal to that of the program. Well, with the possibility of resetting, and joining different servers, this has become less and less true. But for all intents and purposes, Zorn has "one level". DEFINITIONS But what is a level? There are as many concepts as there are descriptions. Here are a few descriptions: level, region, scene, scenario, area, map, arena, game, round, and so on. Each of these (probably) has some meaning in the Zorn application. This text attempts to discover which those are. The first thing approaching levelness in Zorn is the blue, circular border surrounding the game. It is assumed that most Zorn "games" will have such a border (exceptions would have to handle the fact that, as coordinates move away from the center, the resolution gets worse and worse, at least for transmission). We'll call this border, or rather the region of space that it encompasses, the "arena". An "arena" is the fence all action takes place in. Arenas so far have been circular, centered at the origin, and 100 units wide. Of course, in the future, arenas can come in many shapes and sizes. For example, the radius can change. Shifting the origin is thinkable, but has no practical purpose. Squishing the circle to become an oval is also possible. Lastly, the arena can be one or more polygons. The details are immaterial, we have our first definition. The second thing is the "map". The map is not implemented yet, but it used to be visible as the green background grid. A "map" is the definition of which square blocks make up the background. In a near-future Zorn release, each square can be filled or unfilled, and colliding with a filled square will be painful! These blocks can build asteroids, tunnels, or walls. Actually, there will be more than two blocks. We can have diagonal walls, force fields, station parts, grass, whatever the actual game needs. Again, the details are unimportant. We have our next part, the two-dimensional array known as the "map". The final component, for now, is the "scenario". This combines an arena, a map, floating asteroids, enemy spawn points, power-ups, warp fields and anything else we "see". The scenario will most likely be a python class or module, instantiated by the server, which adds all the objects and handlers and has a "run" method somewhere. Again, the details are not important know, only that "someone who takes care of stuff" exists. There are more considerations. For example, a scenario might want to contain several separate-yet-linked arenas, each with their own map and object list. We'll call one such arena-map-objects-handlers collection a "region", and let a scenario contain multiple regions. Another consideration is how easy we allow reuse. Two or more scenarios can use the same map, for example. What about enemy spawn points? What about game types ("capture the flag" vs. "deathmatch")? Can the client cache these somehow? It would be nice to have these separable, but for now, we'll concentrate on single scenarios (with a single region). NETWORKING Now that we've defined these entities (arena, map, scenario), let's start in the middle, where the server tells the client what these look like. Also, we'll assume one region per scenario, or rather no regions yet. To transfer an arena, we need to transfer its type and some parameters. Let's let the single message describing the arena be "AREN". The first byte of the body is the type: 0 for a circle or oval, 1 for a polygon. Let's skip the circle / oval distinction for now, even though we currently only support ovals with identical radii. For a circle or oval, the next two parameters describe the radii (x, then y). We can save space by demanding that the radii are positive integers, but we probably shouldn't. It would only mean four bytes, anyway. We can describe a polygon with a series of 2D points. It remains to be seen how many points an arena can be made of, and whether these need to be integers. Side note: internally, a circle could be represented by a polygon, except that collision detection works *so* much easier with an actual circle or oval. Side note 2: Objects need a "reflect()" method. The map: A map is a twodimensional array, probably of scalars, which are probably single bytes. The first thing to be transmitted is the size of the map, with the "MAPS" message. Should this clear the map? Probably. The two parameters of this message are the width and height of the map. We can save a bit by demanding that the map extents be symmetric about the origin. If the map width and height are 16 bit unsigned numbers, this gives us a maximal side length of 131070! On the other hand, we couldn't index them easily, so let's say the maximal map side length is 65535, or 0xFFFF. The next part is the map contents. We'll define a "MAPC" method (for map contents). Since we can't transmit the entire map in one message, and we probably don't want to in any case, we'll make it more powerful than that, and transmit map patches. A MAPC message starts with four unsigned 16-bit parameters: the x and y coordinate of the top left corner of the patch being transmitted, and then the width and height of the patch. Then comes the patch data, as a bunch of bytes, row-first, no alignment. Side note: If we keep the map centered at the origin, we can use signed coordinates instead of unsigned. If we worked creatively, we wouldn't have to specify a map size at all, even! I'll need to think about this. The scenario: this needs no special transmission. New objects and occurrences are transmitted the usual way. A MOTD is about the most we need to transmit. SEQUENCE OF CHANGE Now that we have the mechanics, let's brainstorm about the sequence once the level changes. A similar sequence is needed when a player joins mid-game. Here, "level" is a synonym for scenario, though with several rounds in the same map, the scenario need not actually change. First, the server decides that the level should change. This is an important step that can't be skipped, despite the fact that nothing happens here. But it is a fundamental one: a level change is immediate and unavoidable. Any decisions that are necessary have been made, this is it. Second, the server destroys any previous scenario, along with any objects (even player objects) inside. Players have their object references removed, but switching them to "need an object" status comes later. Third, the server sends a message to the clients that they, too, should reset (REST). The clients destroy their scenario representations, their objects, their graphical effects etc. Stuff like the chat window should remain, stuff like the scoreboard probably shouldn't. Maybe we can make the REST message contain a bitmap what to reset. For the current standard Zorn game, everything changes. Fourth, the server creates the new scenario. This in turn creates a new arena, map, and handlers, but no objects yet. All players are marked as "need an object", if applicable (this may not be the case if players need to choose their type of object, or spawn point or anything first). Fifth, the server sends the arena boundary to the clients. In fact, this can occur later or not at all, in which case the clients assume a standard circular 100-unit-wide border. Side note: dynamically changing the border as a game element! Especially with polygons, this opens previously unreachable parts. Kinda breaks immersion, though. Sixth, the server sends the map size to the clients. Again, without this message, a standard empty 0 by 0 map is assumed. Seventh, players are sent their CAME coordinates. Without player objects, these are two coordinate numbers, probably of the player spawn point. Without this message, it defaults to (0,0). Eighth, the game itself starts. It will probably kick off with a time control message, setting the time factor to 0.0 for a few seconds. Objects are created. Player objects are created and assigned. These are communicated to the clients normally. Ninth, the server *starts* sending the map data to the clients. Remember that we can transmit arbitrary map patches per message! A simple solution would be to slice the map into regular patches, and transmit the next untransmitted one closest to the player. This needs two things: 1) a per-player list of untransmitted map patches, and 2) a patch-to-player distance measure, probably something like "sum of minimal player-to-border distance". If no player object has been created yet, the player's origin is the same as the CAME coordinates above. JOINING If a player joins a game, pick up with the fifth step. The client has already reset the game. CONCLUSION This essay turned out to describe the status quo, except for on-demand player object creation. And the map, which does not exist at the time of writing. Let's look into the future a bit. LOUNGE Between games, players need a place to connect, chat, set game settings etc. Maybe this can be inside a paused minimal game, instead, containing no objects. Especially if the chat window remains and a new game can be set from the menu. The players will eventually need a way to look at the new map settings 1) as the admin selects them, 2) before joining a server. Later, though. CACHING If we transmit the name of the map, clients may be able to cache it on their disks, allowing a smoother transmission of the map. GAME OVER Currently, there is no game over. This should change once scenarios contain achievable goals. If a scenario detects a game over condition, it should slow the game to 0.0. After a certain time, or when all players have agreed, we can reset or change the scenario, or switch to the lounge.