// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // $Id:$ // // Copyright (C) 1993-1996 by id Software, Inc. // // This source is available for distribution and/or modification // only under the terms of the DOOM Source Code License as // published by id Software. All rights reserved. // // The source is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License // for more details. // // $Log:$ // // DESCRIPTION: // Do all the WAD I/O, get map description, // set up initial state and misc. LUTs. // //----------------------------------------------------------------------------- static const char rcsid[] = "$Id: p_setup.c,v 1.5 1997/02/03 22:45:12 b1 Exp $"; #include #include "z_zone.h" #include "m_swap.h" #include "m_bbox.h" #include "g_game.h" #include "i_system.h" #include "w_wad.h" #include "doomdef.h" #include "p_local.h" #include "s_sound.h" #include "doomstat.h" void P_SpawnMapThing (mapthing_t* mthing); // // MAP related Lookup tables. // Store VERTEXES, LINEDEFS, SIDEDEFS, etc. // int numvertexes; vertex_t* vertexes; int numsegs; seg_t* segs; int numsectors; sector_t* sectors; int numsubsectors; subsector_t* subsectors; int numnodes; node_t* nodes; int numlines; line_t* lines; int numsides; side_t* sides; // BLOCKMAP // Created from axis aligned bounding box // of the map, a rectangular array of // blocks of size ... // Used to speed up collision detection // by spatial subdivision in 2D. // // Blockmap size. int bmapwidth; int bmapheight; // size in mapblocks short* blockmap; // int for larger maps // offsets in blockmap are from here short* blockmaplump; // origin of block map fixed_t bmaporgx; fixed_t bmaporgy; // for thing chains mobj_t** blocklinks; // REJECT // For fast sight rejection. // Speeds up enemy AI by skipping detailed // LineOf Sight calculation. // Without special effect, this could be // used as a PVS lookup as well. // byte* rejectmatrix; // Maintain single and multi player starting spots. #define MAX_DEATHMATCH_STARTS 10 mapthing_t deathmatchstarts[MAX_DEATHMATCH_STARTS]; mapthing_t* deathmatch_p; mapthing_t playerstarts[MAXPLAYERS]; // // P_LoadVertexes // void P_LoadVertexes (int lump) { byte* data; int i; mapvertex_t* ml; vertex_t* li; // Determine number of lumps: // total lump length / vertex record length. numvertexes = W_LumpLength (lump) / sizeof(mapvertex_t); // Allocate zone memory for buffer. vertexes = Z_Malloc (numvertexes*sizeof(vertex_t),PU_LEVEL,0); // Load data into cache. data = W_CacheLumpNum (lump,PU_STATIC); ml = (mapvertex_t *)data; li = vertexes; // Copy and convert vertex coordinates, // internal representation as fixed. for (i=0 ; ix = SHORT(ml->x)<y = SHORT(ml->y)<v1 = &vertexes[SHORT(ml->v1)]; li->v2 = &vertexes[SHORT(ml->v2)]; li->angle = (SHORT(ml->angle))<<16; li->offset = (SHORT(ml->offset))<<16; linedef = SHORT(ml->linedef); ldef = &lines[linedef]; li->linedef = ldef; side = SHORT(ml->side); li->sidedef = &sides[ldef->sidenum[side]]; li->frontsector = sides[ldef->sidenum[side]].sector; if (ldef-> flags & ML_TWOSIDED) li->backsector = sides[ldef->sidenum[side^1]].sector; else li->backsector = 0; } Z_Free (data); } // // P_LoadSubsectors // void P_LoadSubsectors (int lump) { byte* data; int i; mapsubsector_t* ms; subsector_t* ss; numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t); subsectors = Z_Malloc (numsubsectors*sizeof(subsector_t),PU_LEVEL,0); data = W_CacheLumpNum (lump,PU_STATIC); ms = (mapsubsector_t *)data; memset (subsectors,0, numsubsectors*sizeof(subsector_t)); ss = subsectors; for (i=0 ; inumlines = SHORT(ms->numsegs); ss->firstline = SHORT(ms->firstseg); } Z_Free (data); } // // P_LoadSectors // void P_LoadSectors (int lump) { byte* data; int i; mapsector_t* ms; sector_t* ss; numsectors = W_LumpLength (lump) / sizeof(mapsector_t); sectors = Z_Malloc (numsectors*sizeof(sector_t),PU_LEVEL,0); memset (sectors, 0, numsectors*sizeof(sector_t)); data = W_CacheLumpNum (lump,PU_STATIC); ms = (mapsector_t *)data; ss = sectors; for (i=0 ; ifloorheight = SHORT(ms->floorheight)<ceilingheight = SHORT(ms->ceilingheight)<floorpic = R_FlatNumForName(ms->floorpic); ss->ceilingpic = R_FlatNumForName(ms->ceilingpic); ss->lightlevel = SHORT(ms->lightlevel); ss->special = SHORT(ms->special); ss->tag = SHORT(ms->tag); ss->thinglist = NULL; } Z_Free (data); } // // P_LoadNodes // void P_LoadNodes (int lump) { byte* data; int i; int j; int k; mapnode_t* mn; node_t* no; numnodes = W_LumpLength (lump) / sizeof(mapnode_t); nodes = Z_Malloc (numnodes*sizeof(node_t),PU_LEVEL,0); data = W_CacheLumpNum (lump,PU_STATIC); mn = (mapnode_t *)data; no = nodes; for (i=0 ; ix = SHORT(mn->x)<y = SHORT(mn->y)<dx = SHORT(mn->dx)<dy = SHORT(mn->dy)<children[j] = SHORT(mn->children[j]); for (k=0 ; k<4 ; k++) no->bbox[j][k] = SHORT(mn->bbox[j][k])<type) { case 68: // Arachnotron case 64: // Archvile case 88: // Boss Brain case 89: // Boss Shooter case 69: // Hell Knight case 67: // Mancubus case 71: // Pain Elemental case 65: // Former Human Commando case 66: // Revenant case 84: // Wolf SS spawn = false; break; } } if (spawn == false) break; // Do spawn all other stuff. mt->x = SHORT(mt->x); mt->y = SHORT(mt->y); mt->angle = SHORT(mt->angle); mt->type = SHORT(mt->type); mt->options = SHORT(mt->options); P_SpawnMapThing (mt); } Z_Free (data); } // // P_LoadLineDefs // Also counts secret lines for intermissions. // void P_LoadLineDefs (int lump) { byte* data; int i; maplinedef_t* mld; line_t* ld; vertex_t* v1; vertex_t* v2; numlines = W_LumpLength (lump) / sizeof(maplinedef_t); lines = Z_Malloc (numlines*sizeof(line_t),PU_LEVEL,0); memset (lines, 0, numlines*sizeof(line_t)); data = W_CacheLumpNum (lump,PU_STATIC); mld = (maplinedef_t *)data; ld = lines; for (i=0 ; iflags = SHORT(mld->flags); ld->special = SHORT(mld->special); ld->tag = SHORT(mld->tag); v1 = ld->v1 = &vertexes[SHORT(mld->v1)]; v2 = ld->v2 = &vertexes[SHORT(mld->v2)]; ld->dx = v2->x - v1->x; ld->dy = v2->y - v1->y; if (!ld->dx) ld->slopetype = ST_VERTICAL; else if (!ld->dy) ld->slopetype = ST_HORIZONTAL; else { if (FixedDiv (ld->dy , ld->dx) > 0) ld->slopetype = ST_POSITIVE; else ld->slopetype = ST_NEGATIVE; } if (v1->x < v2->x) { ld->bbox[BOXLEFT] = v1->x; ld->bbox[BOXRIGHT] = v2->x; } else { ld->bbox[BOXLEFT] = v2->x; ld->bbox[BOXRIGHT] = v1->x; } if (v1->y < v2->y) { ld->bbox[BOXBOTTOM] = v1->y; ld->bbox[BOXTOP] = v2->y; } else { ld->bbox[BOXBOTTOM] = v2->y; ld->bbox[BOXTOP] = v1->y; } ld->sidenum[0] = SHORT(mld->sidenum[0]); ld->sidenum[1] = SHORT(mld->sidenum[1]); if (ld->sidenum[0] != -1) ld->frontsector = sides[ld->sidenum[0]].sector; else ld->frontsector = 0; if (ld->sidenum[1] != -1) ld->backsector = sides[ld->sidenum[1]].sector; else ld->backsector = 0; } Z_Free (data); } // // P_LoadSideDefs // void P_LoadSideDefs (int lump) { byte* data; int i; mapsidedef_t* msd; side_t* sd; numsides = W_LumpLength (lump) / sizeof(mapsidedef_t); sides = Z_Malloc (numsides*sizeof(side_t),PU_LEVEL,0); memset (sides, 0, numsides*sizeof(side_t)); data = W_CacheLumpNum (lump,PU_STATIC); msd = (mapsidedef_t *)data; sd = sides; for (i=0 ; itextureoffset = SHORT(msd->textureoffset)<rowoffset = SHORT(msd->rowoffset)<toptexture = R_TextureNumForName(msd->toptexture); sd->bottomtexture = R_TextureNumForName(msd->bottomtexture); sd->midtexture = R_TextureNumForName(msd->midtexture); sd->sector = §ors[SHORT(msd->sector)]; } Z_Free (data); } // // P_LoadBlockMap // void P_LoadBlockMap (int lump) { int i; int count; blockmaplump = W_CacheLumpNum (lump,PU_LEVEL); blockmap = blockmaplump+4; count = W_LumpLength (lump)/2; for (i=0 ; ifirstline]; ss->sector = seg->sidedef->sector; } // count number of lines in each sector li = lines; total = 0; for (i=0 ; ifrontsector->linecount++; if (li->backsector && li->backsector != li->frontsector) { li->backsector->linecount++; total++; } } // build line tables for each sector linebuffer = Z_Malloc (total*4, PU_LEVEL, 0); sector = sectors; for (i=0 ; ilines = linebuffer; li = lines; for (j=0 ; jfrontsector == sector || li->backsector == sector) { *linebuffer++ = li; M_AddToBox (bbox, li->v1->x, li->v1->y); M_AddToBox (bbox, li->v2->x, li->v2->y); } } if (linebuffer - sector->lines != sector->linecount) I_Error ("P_GroupLines: miscounted"); // set the degenmobj_t to the middle of the bounding box sector->soundorg.x = (bbox[BOXRIGHT]+bbox[BOXLEFT])/2; sector->soundorg.y = (bbox[BOXTOP]+bbox[BOXBOTTOM])/2; // adjust bounding box to map blocks block = (bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT; block = block >= bmapheight ? bmapheight-1 : block; sector->blockbox[BOXTOP]=block; block = (bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT; block = block < 0 ? 0 : block; sector->blockbox[BOXBOTTOM]=block; block = (bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT; block = block >= bmapwidth ? bmapwidth-1 : block; sector->blockbox[BOXRIGHT]=block; block = (bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT; block = block < 0 ? 0 : block; sector->blockbox[BOXLEFT]=block; } } // // P_SetupLevel // void P_SetupLevel ( int episode, int map, int playermask, skill_t skill) { int i; char lumpname[9]; int lumpnum; totalkills = totalitems = totalsecret = wminfo.maxfrags = 0; wminfo.partime = 180; for (i=0 ; i 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
# Advanced Keycodes

Your keymap can include keycodes that are more advanced than normal, for example keys that switch layers or send modifiers when held, but send regular keycodes when tapped. This page documents the functions that are available to you.

## Assigning Custom Names

People often define custom names using `#define`. For example:

```c
#define FN_CAPS LT(_FL, KC_CAPSLOCK)
#define ALT_TAB LALT(KC_TAB)
```

This will allow you to use `FN_CAPS` and `ALT_TAB` in your keymap, keeping it more readable.

## Caveats

Currently, `LT()` and `MT()` are limited to the [Basic Keycode set](keycodes_basic.md), meaning you can't use keycodes like `LCTL()`, `KC_TILD`, or anything greater than `0xFF`. Modifiers specified as part of a Layer Tap or Mod Tap's keycode will be ignored. If you need to apply modifiers to your tapped keycode, [Tap Dance](feature_tap_dance.md#example-5-using-tap-dance-for-advanced-mod-tap-and-layer-tap-keys) can be used to accomplish this.

Additionally, if at least one right-handed modifier is specified in a Mod Tap or Layer Tap, it will cause all modifiers specified to become right-handed, so it is not possible to mix and match the two.

# Switching and Toggling Layers

These functions allow you to activate layers in various ways. Note that layers are not generally independent layouts -- multiple layers can be activated at once, and it's typical for layers to use `KC_TRNS` to allow keypresses to pass through to lower layers. For a detailed explanation of layers, see [Keymap Overview](keymap.md#keymap-and-layers). When using momentary layer switching with MO(), LM(), TT(), or LT(), make sure to leave the key on the above layers transparent or it may not work as intended.

* `DF(layer)` - switches the default layer. The default layer is the always-active base layer that other layers stack on top of. See below for more about the default layer. This might be used to switch from QWERTY to Dvorak layout. (Note that this is a temporary switch that only persists until the keyboard loses power. To modify the default layer in a persistent way requires deeper customization, such as calling the `set_single_persistent_default_layer` function inside of [process_record_user](custom_quantum_functions.md#programming-the-behavior-of-any-keycode).)