Merge branch 'doom' into 'master'

Doom Port

See merge request 
This commit is contained in:
Alexandre Lavoie 2024-06-04 04:18:48 +00:00
commit f94c0645e7
172 changed files with 63290 additions and 0 deletions

11
apps/doom.ini Normal file
View File

@ -0,0 +1,11 @@
[general]
name=DOOM
permission_all_files=1
use_single_instance=1
[build]
source=apps/doom/essence/main.c
[embed]
$Icons/16=res/DOOM/icon16.png
$Icons/32=res/DOOM/icon32.png

1347
apps/doom/am_map.c Normal file

File diff suppressed because it is too large Load Diff

49
apps/doom/am_map.h Normal file
View File

@ -0,0 +1,49 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// AutoMap module.
//
#ifndef __AMMAP_H__
#define __AMMAP_H__
#include "d_event.h"
#include "m_cheat.h"
// Used by ST StatusBar stuff.
#define AM_MSGHEADER (('a'<<24)+('m'<<16))
#define AM_MSGENTERED (AM_MSGHEADER | ('e'<<8))
#define AM_MSGEXITED (AM_MSGHEADER | ('x'<<8))
// Called by main loop.
boolean AM_Responder (event_t* ev);
// Called by main loop.
void AM_Ticker (void);
// Called by main loop,
// called instead of view drawer if automap active.
void AM_Drawer (void);
// Called to force the automap to quit
// if the level is completed while it is up.
void AM_Stop (void);
extern cheatseq_t cheat_amap;
#endif

50
apps/doom/config.h Normal file
View File

@ -0,0 +1,50 @@
#ifndef __CONFIG__
#define __CONFIG__
/* Define to the full name of this package. */
#define PACKAGE_NAME "Doom Essence"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "Doom Essence 0.1"
/* Change this when you create your awesome forked version */
#define PROGRAM_PREFIX "doomessence"
/* Enables multiplayer support (network games) */
#undef FEATURE_MULTIPLAYER
/* Enables sound output */
#undef FEATURE_SOUND
/* Enabled console debug */
#undef FEATURE_CONSOLE
/* Define to the directory where all game files are located */
#define FILES_DIR "|Settings:/WAD"
/* Define temporary directory path */
#define TMP_DIR "|Settings:/TMP"
/* Define screen resolution */
#define RES_X 640
#define RES_Y 400
/* Define game configs */
#define INITIAL_HEALTH 100
#define INITIAL_BULLETS 50
#define MAX_HEALTH 200
#define MAX_ARMOR 200
#define GREEN_ARMOR_CLASS 1
#define BLUE_ARMOR_CLASS 2
#define MAX_SOULSPHERE 200
#define SOULSPHERE_HEALTH 100
#define MEGASPHERE_HEALTH 200
#define GOD_MODE_HEALTH 100
#define IDFA_ARMOR 200
#define IDFA_ARMOR_CLASS 2
#define IDKFA_ARMOR 200
#define IDKFA_ARMOR_CLASS 2
#define BFG_CELLS_PER_SHOT 40
#define SPECIES_INFIGHTING 0
#endif

693
apps/doom/d_englsh.h Normal file
View File

@ -0,0 +1,693 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Printed strings for translation.
// English language support (default).
//
#ifndef __D_ENGLSH__
#define __D_ENGLSH__
//
// Printed strings for translation
//
//
// D_Main.C
//
#define D_DEVSTR "Development mode ON.\n"
#define D_CDROM "CD-ROM Version: default.cfg from c:\\doomdata\n"
//
// M_Menu.C
//
#define PRESSKEY "press a key."
#define PRESSYN "press y or n."
#define QUITMSG "are you sure you want to\nquit this great game?"
#define LOADNET "you can't do load while in a net game!\n\n"PRESSKEY
#define QLOADNET "you can't quickload during a netgame!\n\n"PRESSKEY
#define QSAVESPOT "you haven't picked a quicksave slot yet!\n\n"PRESSKEY
#define SAVEDEAD "you can't save if you aren't playing!\n\n"PRESSKEY
#define QSPROMPT "quicksave over your game named\n\n'%s'?\n\n"PRESSYN
#define QLPROMPT "do you want to quickload the game named\n\n'%s'?\n\n"PRESSYN
#define NEWGAME \
"you can't start a new game\n"\
"while in a network game.\n\n"PRESSKEY
#define NIGHTMARE \
"are you sure? this skill level\n"\
"isn't even remotely fair.\n\n"PRESSYN
#define SWSTRING \
"this is the shareware version of doom.\n\n"\
"you need to order the entire trilogy.\n\n"PRESSKEY
#define MSGOFF "Messages OFF"
#define MSGON "Messages ON"
#define NETEND "you can't end a netgame!\n\n"PRESSKEY
#define ENDGAME "are you sure you want to end the game?\n\n"PRESSYN
#define DOSY "(press y to quit to essence.)"
#define DETAILHI "High detail"
#define DETAILLO "Low detail"
#define GAMMALVL0 "Gamma correction OFF"
#define GAMMALVL1 "Gamma correction level 1"
#define GAMMALVL2 "Gamma correction level 2"
#define GAMMALVL3 "Gamma correction level 3"
#define GAMMALVL4 "Gamma correction level 4"
#define EMPTYSTRING "empty slot"
//
// P_inter.C
//
#define GOTARMOR "Picked up the armor."
#define GOTMEGA "Picked up the MegaArmor!"
#define GOTHTHBONUS "Picked up a health bonus."
#define GOTARMBONUS "Picked up an armor bonus."
#define GOTSTIM "Picked up a stimpack."
#define GOTMEDINEED "Picked up a medikit that you REALLY need!"
#define GOTMEDIKIT "Picked up a medikit."
#define GOTSUPER "Supercharge!"
#define GOTBLUECARD "Picked up a blue keycard."
#define GOTYELWCARD "Picked up a yellow keycard."
#define GOTREDCARD "Picked up a red keycard."
#define GOTBLUESKUL "Picked up a blue skull key."
#define GOTYELWSKUL "Picked up a yellow skull key."
#define GOTREDSKULL "Picked up a red skull key."
#define GOTINVUL "Invulnerability!"
#define GOTBERSERK "Berserk!"
#define GOTINVIS "Partial Invisibility"
#define GOTSUIT "Radiation Shielding Suit"
#define GOTMAP "Computer Area Map"
#define GOTVISOR "Light Amplification Visor"
#define GOTMSPHERE "MegaSphere!"
#define GOTCLIP "Picked up a clip."
#define GOTCLIPBOX "Picked up a box of bullets."
#define GOTROCKET "Picked up a rocket."
#define GOTROCKBOX "Picked up a box of rockets."
#define GOTCELL "Picked up an energy cell."
#define GOTCELLBOX "Picked up an energy cell pack."
#define GOTSHELLS "Picked up 4 shotgun shells."
#define GOTSHELLBOX "Picked up a box of shotgun shells."
#define GOTBACKPACK "Picked up a backpack full of ammo!"
#define GOTBFG9000 "You got the BFG9000! Oh, yes."
#define GOTCHAINGUN "You got the chaingun!"
#define GOTCHAINSAW "A chainsaw! Find some meat!"
#define GOTLAUNCHER "You got the rocket launcher!"
#define GOTPLASMA "You got the plasma gun!"
#define GOTSHOTGUN "You got the shotgun!"
#define GOTSHOTGUN2 "You got the super shotgun!"
//
// P_Doors.C
//
#define PD_BLUEO "You need a blue key to activate this object"
#define PD_REDO "You need a red key to activate this object"
#define PD_YELLOWO "You need a yellow key to activate this object"
#define PD_BLUEK "You need a blue key to open this door"
#define PD_REDK "You need a red key to open this door"
#define PD_YELLOWK "You need a yellow key to open this door"
//
// G_game.C
//
#define GGSAVED "game saved."
//
// HU_stuff.C
//
#define HUSTR_MSGU "[Message unsent]"
#define HUSTR_E1M1 "E1M1: Hangar"
#define HUSTR_E1M2 "E1M2: Nuclear Plant"
#define HUSTR_E1M3 "E1M3: Toxin Refinery"
#define HUSTR_E1M4 "E1M4: Command Control"
#define HUSTR_E1M5 "E1M5: Phobos Lab"
#define HUSTR_E1M6 "E1M6: Central Processing"
#define HUSTR_E1M7 "E1M7: Computer Station"
#define HUSTR_E1M8 "E1M8: Phobos Anomaly"
#define HUSTR_E1M9 "E1M9: Military Base"
#define HUSTR_E2M1 "E2M1: Deimos Anomaly"
#define HUSTR_E2M2 "E2M2: Containment Area"
#define HUSTR_E2M3 "E2M3: Refinery"
#define HUSTR_E2M4 "E2M4: Deimos Lab"
#define HUSTR_E2M5 "E2M5: Command Center"
#define HUSTR_E2M6 "E2M6: Halls of the Damned"
#define HUSTR_E2M7 "E2M7: Spawning Vats"
#define HUSTR_E2M8 "E2M8: Tower of Babel"
#define HUSTR_E2M9 "E2M9: Fortress of Mystery"
#define HUSTR_E3M1 "E3M1: Hell Keep"
#define HUSTR_E3M2 "E3M2: Slough of Despair"
#define HUSTR_E3M3 "E3M3: Pandemonium"
#define HUSTR_E3M4 "E3M4: House of Pain"
#define HUSTR_E3M5 "E3M5: Unholy Cathedral"
#define HUSTR_E3M6 "E3M6: Mt. Erebus"
#define HUSTR_E3M7 "E3M7: Limbo"
#define HUSTR_E3M8 "E3M8: Dis"
#define HUSTR_E3M9 "E3M9: Warrens"
#define HUSTR_E4M1 "E4M1: Hell Beneath"
#define HUSTR_E4M2 "E4M2: Perfect Hatred"
#define HUSTR_E4M3 "E4M3: Sever The Wicked"
#define HUSTR_E4M4 "E4M4: Unruly Evil"
#define HUSTR_E4M5 "E4M5: They Will Repent"
#define HUSTR_E4M6 "E4M6: Against Thee Wickedly"
#define HUSTR_E4M7 "E4M7: And Hell Followed"
#define HUSTR_E4M8 "E4M8: Unto The Cruel"
#define HUSTR_E4M9 "E4M9: Fear"
#define HUSTR_1 "level 1: entryway"
#define HUSTR_2 "level 2: underhalls"
#define HUSTR_3 "level 3: the gantlet"
#define HUSTR_4 "level 4: the focus"
#define HUSTR_5 "level 5: the waste tunnels"
#define HUSTR_6 "level 6: the crusher"
#define HUSTR_7 "level 7: dead simple"
#define HUSTR_8 "level 8: tricks and traps"
#define HUSTR_9 "level 9: the pit"
#define HUSTR_10 "level 10: refueling base"
#define HUSTR_11 "level 11: 'o' of destruction!"
#define HUSTR_12 "level 12: the factory"
#define HUSTR_13 "level 13: downtown"
#define HUSTR_14 "level 14: the inmost dens"
#define HUSTR_15 "level 15: industrial zone"
#define HUSTR_16 "level 16: suburbs"
#define HUSTR_17 "level 17: tenements"
#define HUSTR_18 "level 18: the courtyard"
#define HUSTR_19 "level 19: the citadel"
#define HUSTR_20 "level 20: gotcha!"
#define HUSTR_21 "level 21: nirvana"
#define HUSTR_22 "level 22: the catacombs"
#define HUSTR_23 "level 23: barrels o' fun"
#define HUSTR_24 "level 24: the chasm"
#define HUSTR_25 "level 25: bloodfalls"
#define HUSTR_26 "level 26: the abandoned mines"
#define HUSTR_27 "level 27: monster condo"
#define HUSTR_28 "level 28: the spirit world"
#define HUSTR_29 "level 29: the living end"
#define HUSTR_30 "level 30: icon of sin"
#define HUSTR_31 "level 31: wolfenstein"
#define HUSTR_32 "level 32: grosse"
#define PHUSTR_1 "level 1: congo"
#define PHUSTR_2 "level 2: well of souls"
#define PHUSTR_3 "level 3: aztec"
#define PHUSTR_4 "level 4: caged"
#define PHUSTR_5 "level 5: ghost town"
#define PHUSTR_6 "level 6: baron's lair"
#define PHUSTR_7 "level 7: caughtyard"
#define PHUSTR_8 "level 8: realm"
#define PHUSTR_9 "level 9: abattoire"
#define PHUSTR_10 "level 10: onslaught"
#define PHUSTR_11 "level 11: hunted"
#define PHUSTR_12 "level 12: speed"
#define PHUSTR_13 "level 13: the crypt"
#define PHUSTR_14 "level 14: genesis"
#define PHUSTR_15 "level 15: the twilight"
#define PHUSTR_16 "level 16: the omen"
#define PHUSTR_17 "level 17: compound"
#define PHUSTR_18 "level 18: neurosphere"
#define PHUSTR_19 "level 19: nme"
#define PHUSTR_20 "level 20: the death domain"
#define PHUSTR_21 "level 21: slayer"
#define PHUSTR_22 "level 22: impossible mission"
#define PHUSTR_23 "level 23: tombstone"
#define PHUSTR_24 "level 24: the final frontier"
#define PHUSTR_25 "level 25: the temple of darkness"
#define PHUSTR_26 "level 26: bunker"
#define PHUSTR_27 "level 27: anti-christ"
#define PHUSTR_28 "level 28: the sewers"
#define PHUSTR_29 "level 29: odyssey of noises"
#define PHUSTR_30 "level 30: the gateway of hell"
#define PHUSTR_31 "level 31: cyberden"
#define PHUSTR_32 "level 32: go 2 it"
#define THUSTR_1 "level 1: system control"
#define THUSTR_2 "level 2: human bbq"
#define THUSTR_3 "level 3: power control"
#define THUSTR_4 "level 4: wormhole"
#define THUSTR_5 "level 5: hanger"
#define THUSTR_6 "level 6: open season"
#define THUSTR_7 "level 7: prison"
#define THUSTR_8 "level 8: metal"
#define THUSTR_9 "level 9: stronghold"
#define THUSTR_10 "level 10: redemption"
#define THUSTR_11 "level 11: storage facility"
#define THUSTR_12 "level 12: crater"
#define THUSTR_13 "level 13: nukage processing"
#define THUSTR_14 "level 14: steel works"
#define THUSTR_15 "level 15: dead zone"
#define THUSTR_16 "level 16: deepest reaches"
#define THUSTR_17 "level 17: processing area"
#define THUSTR_18 "level 18: mill"
#define THUSTR_19 "level 19: shipping/respawning"
#define THUSTR_20 "level 20: central processing"
#define THUSTR_21 "level 21: administration center"
#define THUSTR_22 "level 22: habitat"
#define THUSTR_23 "level 23: lunar mining project"
#define THUSTR_24 "level 24: quarry"
#define THUSTR_25 "level 25: baron's den"
#define THUSTR_26 "level 26: ballistyx"
#define THUSTR_27 "level 27: mount pain"
#define THUSTR_28 "level 28: heck"
#define THUSTR_29 "level 29: river styx"
#define THUSTR_30 "level 30: last call"
#define THUSTR_31 "level 31: pharaoh"
#define THUSTR_32 "level 32: caribbean"
#define HUSTR_CHATMACRO1 "I'm ready to kick butt!"
#define HUSTR_CHATMACRO2 "I'm OK."
#define HUSTR_CHATMACRO3 "I'm not looking too good!"
#define HUSTR_CHATMACRO4 "Help!"
#define HUSTR_CHATMACRO5 "You suck!"
#define HUSTR_CHATMACRO6 "Next time, scumbag..."
#define HUSTR_CHATMACRO7 "Come here!"
#define HUSTR_CHATMACRO8 "I'll take care of it."
#define HUSTR_CHATMACRO9 "Yes"
#define HUSTR_CHATMACRO0 "No"
#define HUSTR_TALKTOSELF1 "You mumble to yourself"
#define HUSTR_TALKTOSELF2 "Who's there?"
#define HUSTR_TALKTOSELF3 "You scare yourself"
#define HUSTR_TALKTOSELF4 "You start to rave"
#define HUSTR_TALKTOSELF5 "You've lost it..."
#define HUSTR_MESSAGESENT "[Message Sent]"
// The following should NOT be changed unless it seems
// just AWFULLY necessary
#define HUSTR_PLRGREEN "Green: "
#define HUSTR_PLRINDIGO "Indigo: "
#define HUSTR_PLRBROWN "Brown: "
#define HUSTR_PLRRED "Red: "
#define HUSTR_KEYGREEN 'g'
#define HUSTR_KEYINDIGO 'i'
#define HUSTR_KEYBROWN 'b'
#define HUSTR_KEYRED 'r'
//
// AM_map.C
//
#define AMSTR_FOLLOWON "Follow Mode ON"
#define AMSTR_FOLLOWOFF "Follow Mode OFF"
#define AMSTR_GRIDON "Grid ON"
#define AMSTR_GRIDOFF "Grid OFF"
#define AMSTR_MARKEDSPOT "Marked Spot"
#define AMSTR_MARKSCLEARED "All Marks Cleared"
//
// ST_stuff.C
//
#define STSTR_MUS "Music Change"
#define STSTR_NOMUS "IMPOSSIBLE SELECTION"
#define STSTR_DQDON "Degreelessness Mode On"
#define STSTR_DQDOFF "Degreelessness Mode Off"
#define STSTR_KFAADDED "Very Happy Ammo Added"
#define STSTR_FAADDED "Ammo (no keys) Added"
#define STSTR_NCON "No Clipping Mode ON"
#define STSTR_NCOFF "No Clipping Mode OFF"
#define STSTR_BEHOLD "inVuln, Str, Inviso, Rad, Allmap, or Lite-amp"
#define STSTR_BEHOLDX "Power-up Toggled"
#define STSTR_CHOPPERS "... doesn't suck - GM"
#define STSTR_CLEV "Changing Level..."
//
// F_Finale.C
//
#define E1TEXT \
"Once you beat the big badasses and\n"\
"clean out the moon base you're supposed\n"\
"to win, aren't you? Aren't you? Where's\n"\
"your fat reward and ticket home? What\n"\
"the hell is this? It's not supposed to\n"\
"end this way!\n"\
"\n" \
"It stinks like rotten meat, but looks\n"\
"like the lost Deimos base. Looks like\n"\
"you're stuck on The Shores of Hell.\n"\
"The only way out is through.\n"\
"\n"\
"To continue the DOOM experience, play\n"\
"The Shores of Hell and its amazing\n"\
"sequel, Inferno!\n"
#define E2TEXT \
"You've done it! The hideous cyber-\n"\
"demon lord that ruled the lost Deimos\n"\
"moon base has been slain and you\n"\
"are triumphant! But ... where are\n"\
"you? You clamber to the edge of the\n"\
"moon and look down to see the awful\n"\
"truth.\n" \
"\n"\
"Deimos floats above Hell itself!\n"\
"You've never heard of anyone escaping\n"\
"from Hell, but you'll make the bastards\n"\
"sorry they ever heard of you! Quickly,\n"\
"you rappel down to the surface of\n"\
"Hell.\n"\
"\n" \
"Now, it's on to the final chapter of\n"\
"DOOM! -- Inferno."
#define E3TEXT \
"The loathsome spiderdemon that\n"\
"masterminded the invasion of the moon\n"\
"bases and caused so much death has had\n"\
"its ass kicked for all time.\n"\
"\n"\
"A hidden doorway opens and you enter.\n"\
"You've proven too tough for Hell to\n"\
"contain, and now Hell at last plays\n"\
"fair -- for you emerge from the door\n"\
"to see the green fields of Earth!\n"\
"Home at last.\n" \
"\n"\
"You wonder what's been happening on\n"\
"Earth while you were battling evil\n"\
"unleashed. It's good that no Hell-\n"\
"spawn could have come through that\n"\
"door with you ..."
#define E4TEXT \
"the spider mastermind must have sent forth\n"\
"its legions of hellspawn before your\n"\
"final confrontation with that terrible\n"\
"beast from hell. but you stepped forward\n"\
"and brought forth eternal damnation and\n"\
"suffering upon the horde as a true hero\n"\
"would in the face of something so evil.\n"\
"\n"\
"besides, someone was gonna pay for what\n"\
"happened to daisy, your pet rabbit.\n"\
"\n"\
"but now, you see spread before you more\n"\
"potential pain and gibbitude as a nation\n"\
"of demons run amok among our cities.\n"\
"\n"\
"next stop, hell on earth!"
// after level 6, put this:
#define C1TEXT \
"YOU HAVE ENTERED DEEPLY INTO THE INFESTED\n" \
"STARPORT. BUT SOMETHING IS WRONG. THE\n" \
"MONSTERS HAVE BROUGHT THEIR OWN REALITY\n" \
"WITH THEM, AND THE STARPORT'S TECHNOLOGY\n" \
"IS BEING SUBVERTED BY THEIR PRESENCE.\n" \
"\n"\
"AHEAD, YOU SEE AN OUTPOST OF HELL, A\n" \
"FORTIFIED ZONE. IF YOU CAN GET PAST IT,\n" \
"YOU CAN PENETRATE INTO THE HAUNTED HEART\n" \
"OF THE STARBASE AND FIND THE CONTROLLING\n" \
"SWITCH WHICH HOLDS EARTH'S POPULATION\n" \
"HOSTAGE."
// After level 11, put this:
#define C2TEXT \
"YOU HAVE WON! YOUR VICTORY HAS ENABLED\n" \
"HUMANKIND TO EVACUATE EARTH AND ESCAPE\n"\
"THE NIGHTMARE. NOW YOU ARE THE ONLY\n"\
"HUMAN LEFT ON THE FACE OF THE PLANET.\n"\
"CANNIBAL MUTATIONS, CARNIVOROUS ALIENS,\n"\
"AND EVIL SPIRITS ARE YOUR ONLY NEIGHBORS.\n"\
"YOU SIT BACK AND WAIT FOR DEATH, CONTENT\n"\
"THAT YOU HAVE SAVED YOUR SPECIES.\n"\
"\n"\
"BUT THEN, EARTH CONTROL BEAMS DOWN A\n"\
"MESSAGE FROM SPACE: \"SENSORS HAVE LOCATED\n"\
"THE SOURCE OF THE ALIEN INVASION. IF YOU\n"\
"GO THERE, YOU MAY BE ABLE TO BLOCK THEIR\n"\
"ENTRY. THE ALIEN BASE IS IN THE HEART OF\n"\
"YOUR OWN HOME CITY, NOT FAR FROM THE\n"\
"STARPORT.\" SLOWLY AND PAINFULLY YOU GET\n"\
"UP AND RETURN TO THE FRAY."
// After level 20, put this:
#define C3TEXT \
"YOU ARE AT THE CORRUPT HEART OF THE CITY,\n"\
"SURROUNDED BY THE CORPSES OF YOUR ENEMIES.\n"\
"YOU SEE NO WAY TO DESTROY THE CREATURES'\n"\
"ENTRYWAY ON THIS SIDE, SO YOU CLENCH YOUR\n"\
"TEETH AND PLUNGE THROUGH IT.\n"\
"\n"\
"THERE MUST BE A WAY TO CLOSE IT ON THE\n"\
"OTHER SIDE. WHAT DO YOU CARE IF YOU'VE\n"\
"GOT TO GO THROUGH HELL TO GET TO IT?"
// After level 29, put this:
#define C4TEXT \
"THE HORRENDOUS VISAGE OF THE BIGGEST\n"\
"DEMON YOU'VE EVER SEEN CRUMBLES BEFORE\n"\
"YOU, AFTER YOU PUMP YOUR ROCKETS INTO\n"\
"HIS EXPOSED BRAIN. THE MONSTER SHRIVELS\n"\
"UP AND DIES, ITS THRASHING LIMBS\n"\
"DEVASTATING UNTOLD MILES OF HELL'S\n"\
"SURFACE.\n"\
"\n"\
"YOU'VE DONE IT. THE INVASION IS OVER.\n"\
"EARTH IS SAVED. HELL IS A WRECK. YOU\n"\
"WONDER WHERE BAD FOLKS WILL GO WHEN THEY\n"\
"DIE, NOW. WIPING THE SWEAT FROM YOUR\n"\
"FOREHEAD YOU BEGIN THE LONG TREK BACK\n"\
"HOME. REBUILDING EARTH OUGHT TO BE A\n"\
"LOT MORE FUN THAN RUINING IT WAS.\n"
// Before level 31, put this:
#define C5TEXT \
"CONGRATULATIONS, YOU'VE FOUND THE SECRET\n"\
"LEVEL! LOOKS LIKE IT'S BEEN BUILT BY\n"\
"HUMANS, RATHER THAN DEMONS. YOU WONDER\n"\
"WHO THE INMATES OF THIS CORNER OF HELL\n"\
"WILL BE."
// Before level 32, put this:
#define C6TEXT \
"CONGRATULATIONS, YOU'VE FOUND THE\n"\
"SUPER SECRET LEVEL! YOU'D BETTER\n"\
"BLAZE THROUGH THIS ONE!\n"
// after map 06
#define P1TEXT \
"You gloat over the steaming carcass of the\n"\
"Guardian. With its death, you've wrested\n"\
"the Accelerator from the stinking claws\n"\
"of Hell. You relax and glance around the\n"\
"room. Damn! There was supposed to be at\n"\
"least one working prototype, but you can't\n"\
"see it. The demons must have taken it.\n"\
"\n"\
"You must find the prototype, or all your\n"\
"struggles will have been wasted. Keep\n"\
"moving, keep fighting, keep killing.\n"\
"Oh yes, keep living, too."
// after map 11
#define P2TEXT \
"Even the deadly Arch-Vile labyrinth could\n"\
"not stop you, and you've gotten to the\n"\
"prototype Accelerator which is soon\n"\
"efficiently and permanently deactivated.\n"\
"\n"\
"You're good at that kind of thing."
// after map 20
#define P3TEXT \
"You've bashed and battered your way into\n"\
"the heart of the devil-hive. Time for a\n"\
"Search-and-Destroy mission, aimed at the\n"\
"Gatekeeper, whose foul offspring is\n"\
"cascading to Earth. Yeah, he's bad. But\n"\
"you know who's worse!\n"\
"\n"\
"Grinning evilly, you check your gear, and\n"\
"get ready to give the bastard a little Hell\n"\
"of your own making!"
// after map 30
#define P4TEXT \
"The Gatekeeper's evil face is splattered\n"\
"all over the place. As its tattered corpse\n"\
"collapses, an inverted Gate forms and\n"\
"sucks down the shards of the last\n"\
"prototype Accelerator, not to mention the\n"\
"few remaining demons. You're done. Hell\n"\
"has gone back to pounding bad dead folks \n"\
"instead of good live ones. Remember to\n"\
"tell your grandkids to put a rocket\n"\
"launcher in your coffin. If you go to Hell\n"\
"when you die, you'll need it for some\n"\
"final cleaning-up ..."
// before map 31
#define P5TEXT \
"You've found the second-hardest level we\n"\
"got. Hope you have a saved game a level or\n"\
"two previous. If not, be prepared to die\n"\
"aplenty. For master marines only."
// before map 32
#define P6TEXT \
"Betcha wondered just what WAS the hardest\n"\
"level we had ready for ya? Now you know.\n"\
"No one gets out alive."
#define T1TEXT \
"You've fought your way out of the infested\n"\
"experimental labs. It seems that UAC has\n"\
"once again gulped it down. With their\n"\
"high turnover, it must be hard for poor\n"\
"old UAC to buy corporate health insurance\n"\
"nowadays..\n"\
"\n"\
"Ahead lies the military complex, now\n"\
"swarming with diseased horrors hot to get\n"\
"their teeth into you. With luck, the\n"\
"complex still has some warlike ordnance\n"\
"laying around."
#define T2TEXT \
"You hear the grinding of heavy machinery\n"\
"ahead. You sure hope they're not stamping\n"\
"out new hellspawn, but you're ready to\n"\
"ream out a whole herd if you have to.\n"\
"They might be planning a blood feast, but\n"\
"you feel about as mean as two thousand\n"\
"maniacs packed into one mad killer.\n"\
"\n"\
"You don't plan to go down easy."
#define T3TEXT \
"The vista opening ahead looks real damn\n"\
"familiar. Smells familiar, too -- like\n"\
"fried excrement. You didn't like this\n"\
"place before, and you sure as hell ain't\n"\
"planning to like it now. The more you\n"\
"brood on it, the madder you get.\n"\
"Hefting your gun, an evil grin trickles\n"\
"onto your face. Time to take some names."
#define T4TEXT \
"Suddenly, all is silent, from one horizon\n"\
"to the other. The agonizing echo of Hell\n"\
"fades away, the nightmare sky turns to\n"\
"blue, the heaps of monster corpses start \n"\
"to evaporate along with the evil stench \n"\
"that filled the air. Jeeze, maybe you've\n"\
"done it. Have you really won?\n"\
"\n"\
"Something rumbles in the distance.\n"\
"A blue light begins to glow inside the\n"\
"ruined skull of the demon-spitter."
#define T5TEXT \
"What now? Looks totally different. Kind\n"\
"of like King Tut's condo. Well,\n"\
"whatever's here can't be any worse\n"\
"than usual. Can it? Or maybe it's best\n"\
"to let sleeping gods lie.."
#define T6TEXT \
"Time for a vacation. You've burst the\n"\
"bowels of hell and by golly you're ready\n"\
"for a break. You mutter to yourself,\n"\
"Maybe someone else can kick Hell's ass\n"\
"next time around. Ahead lies a quiet town,\n"\
"with peaceful flowing water, quaint\n"\
"buildings, and presumably no Hellspawn.\n"\
"\n"\
"As you step off the transport, you hear\n"\
"the stomp of a cyberdemon's iron shoe."
//
// Character cast strings F_FINALE.C
//
#define CC_ZOMBIE "ZOMBIEMAN"
#define CC_SHOTGUN "SHOTGUN GUY"
#define CC_HEAVY "HEAVY WEAPON DUDE"
#define CC_IMP "IMP"
#define CC_DEMON "DEMON"
#define CC_LOST "LOST SOUL"
#define CC_CACO "CACODEMON"
#define CC_HELL "HELL KNIGHT"
#define CC_BARON "BARON OF HELL"
#define CC_ARACH "ARACHNOTRON"
#define CC_PAIN "PAIN ELEMENTAL"
#define CC_REVEN "REVENANT"
#define CC_MANCU "MANCUBUS"
#define CC_ARCH "ARCH-VILE"
#define CC_SPIDER "THE SPIDER MASTERMIND"
#define CC_CYBER "THE CYBERDEMON"
#define CC_HERO "OUR HERO"
#endif

60
apps/doom/d_event.c Normal file
View File

@ -0,0 +1,60 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// DESCRIPTION: Event handling.
//
// Events are asynchronous inputs generally generated by the game user.
// Events can be discarded if no responder claims them
//
#include "essence/include.h"
#include "d_event.h"
#define MAXEVENTS 64
static event_t events[MAXEVENTS];
static int eventhead;
static int eventtail;
//
// D_PostEvent
// Called by the I/O functions when input is detected
//
void D_PostEvent(event_t* ev)
{
events[eventhead] = *ev;
eventhead = (eventhead + 1) % MAXEVENTS;
}
// Read an event from the queue.
event_t *D_PopEvent(void)
{
event_t *result;
// No more events waiting.
if (eventtail == eventhead)
{
return NULL;
}
result = &events[eventtail];
// Advance to the next event in the queue.
eventtail = (eventtail + 1) % MAXEVENTS;
return result;
}

132
apps/doom/d_event.h Normal file
View File

@ -0,0 +1,132 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
//
//
#ifndef __D_EVENT__
#define __D_EVENT__
#include "doomtype.h"
//
// Event handling.
//
// Input event types.
typedef enum
{
ev_keydown,
ev_keyup,
ev_mouse,
ev_joystick,
ev_quit
} evtype_t;
// Event structure.
typedef struct
{
evtype_t type;
// Event-related data that depends on the type of event:
//
// ev_keydown/ev_keyup:
// data1: Key code (from doomkeys.h) of the key that was
// pressed or released.
// data2: Ascii text of the character that was pressed,
// shifted appropriately (eg. '$' if 4 was pressed
// while shift was held).
//
// ev_mouse:
// data1: Bitfield of buttons currently held down.
// (bit 0 = left; bit 1 = right; bit 2 = middle).
// data2: X axis mouse movement (turn).
// data3: Y axis mouse movement (forward/backward).
//
// ev_joystick:
// data1: Bitfield of buttons currently pressed.
// data2: X axis mouse movement (turn).
// data3: Y axis mouse movement (forward/backward).
// data4: Third axis mouse movement (strafe).
int data1, data2, data3, data4;
} event_t;
//
// Button/action code definitions.
//
typedef enum
{
// Press "Fire".
BT_ATTACK = 1,
// Use button, to open doors, activate switches.
BT_USE = 2,
// Flag: game events, not really buttons.
BT_SPECIAL = 128,
BT_SPECIALMASK = 3,
// Flag, weapon change pending.
// If true, the next 3 bits hold weapon num.
BT_CHANGE = 4,
// The 3bit weapon mask and shift, convenience.
BT_WEAPONMASK = (8+16+32),
BT_WEAPONSHIFT = 3,
// Pause the game.
BTS_PAUSE = 1,
// Save the game at each console.
BTS_SAVEGAME = 2,
// Savegame slot numbers
// occupy the second byte of buttons.
BTS_SAVEMASK = (4+8+16),
BTS_SAVESHIFT = 2,
} buttoncode_t;
// villsa [STRIFE] Strife specific buttons
// TODO - not finished
typedef enum
{
// Player view look up
BT2_LOOKUP = 1,
// Player view look down
BT2_LOOKDOWN = 2,
// Center player's view
BT2_CENTERVIEW = 4,
// Use inventory item
BT2_INVUSE = 8,
// Drop inventory item
BT2_INVDROP = 16,
// Jump up and down
BT2_JUMP = 32,
// Use medkit
BT2_HEALTH = 128,
} buttoncode2_t;
// Called by IO functions when input is detected.
void D_PostEvent (event_t *ev);
// Read an event from the event queue
event_t *D_PopEvent(void);
#endif

128
apps/doom/d_items.c Normal file
View File

@ -0,0 +1,128 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
//
// We are referring to sprite numbers.
#include "info.h"
#include "d_items.h"
//
// PSPRITE ACTIONS for waepons.
// This struct controls the weapon animations.
//
// Each entry is:
// ammo/amunition type
// upstate
// downstate
// readystate
// atkstate, i.e. attack/fire/hit frame
// flashstate, muzzle flash
//
weaponinfo_t weaponinfo[NUMWEAPONS] =
{
{
// fist
am_noammo,
S_PUNCHUP,
S_PUNCHDOWN,
S_PUNCH,
S_PUNCH1,
S_NULL
},
{
// pistol
am_clip,
S_PISTOLUP,
S_PISTOLDOWN,
S_PISTOL,
S_PISTOL1,
S_PISTOLFLASH
},
{
// shotgun
am_shell,
S_SGUNUP,
S_SGUNDOWN,
S_SGUN,
S_SGUN1,
S_SGUNFLASH1
},
{
// chaingun
am_clip,
S_CHAINUP,
S_CHAINDOWN,
S_CHAIN,
S_CHAIN1,
S_CHAINFLASH1
},
{
// missile launcher
am_misl,
S_MISSILEUP,
S_MISSILEDOWN,
S_MISSILE,
S_MISSILE1,
S_MISSILEFLASH1
},
{
// plasma rifle
am_cell,
S_PLASMAUP,
S_PLASMADOWN,
S_PLASMA,
S_PLASMA1,
S_PLASMAFLASH1
},
{
// bfg 9000
am_cell,
S_BFGUP,
S_BFGDOWN,
S_BFG,
S_BFG1,
S_BFGFLASH1
},
{
// chainsaw
am_noammo,
S_SAWUP,
S_SAWDOWN,
S_SAW,
S_SAW1,
S_NULL
},
{
// super shotgun
am_shell,
S_DSGUNUP,
S_DSGUNDOWN,
S_DSGUN,
S_DSGUN1,
S_DSGUNFLASH1
},
};

41
apps/doom/d_items.h Normal file
View File

@ -0,0 +1,41 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Items: key cards, artifacts, weapon, ammunition.
//
#ifndef __D_ITEMS__
#define __D_ITEMS__
#include "doomdef.h"
// Weapon info: sprite frames, ammunition use.
typedef struct
{
ammotype_t ammo;
int upstate;
int downstate;
int readystate;
int atkstate;
int flashstate;
} weaponinfo_t;
extern weaponinfo_t weaponinfo[NUMWEAPONS];
#endif

427
apps/doom/d_iwad.c Normal file
View File

@ -0,0 +1,427 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Search for and locate an IWAD file, and initialize according
// to the IWAD type.
//
#include "essence/include.h"
#include "config.h"
#include "doomkeys.h"
#include "d_iwad.h"
#include "i_system.h"
#include "m_argv.h"
#include "m_config.h"
#include "m_misc.h"
#include "w_wad.h"
#include "z_zone.h"
static const iwad_t iwads[] =
{
{ "doom2.wad", doom2, commercial, "Doom II" },
{ "plutonia.wad", pack_plut, commercial, "Final Doom: Plutonia Experiment" },
{ "tnt.wad", pack_tnt, commercial, "Final Doom: TNT: Evilution" },
{ "doom.wad", doom, retail, "Doom" },
{ "doom1.wad", doom, shareware, "Doom Shareware" },
{ "chex.wad", pack_chex, shareware, "Chex Quest" },
{ "hacx.wad", pack_hacx, commercial, "Hacx" },
{ "freedm.wad", doom2, commercial, "FreeDM" },
{ "freedoom2.wad", doom2, commercial, "Freedoom: Phase 2" },
{ "freedoom1.wad", doom, retail, "Freedoom: Phase 1" },
{ "heretic.wad", heretic, retail, "Heretic" },
{ "heretic1.wad", heretic, shareware, "Heretic Shareware" },
{ "hexen.wad", hexen, commercial, "Hexen" },
{ "strife1.wad", strife, commercial, "Strife" },
};
// Array of locations to search for IWAD files
//
// "128 IWAD search directories should be enough for anybody".
#define MAX_IWAD_DIRS 128
static boolean iwad_dirs_built = false;
static char *iwad_dirs[MAX_IWAD_DIRS];
static int num_iwad_dirs = 0;
static void AddIWADDir(char *dir)
{
if (num_iwad_dirs < MAX_IWAD_DIRS)
{
iwad_dirs[num_iwad_dirs] = dir;
++num_iwad_dirs;
}
}
// Returns true if the specified path is a path to a file
// of the specified name.
static boolean DirIsFile(char *path, char *filename)
{
size_t path_len;
size_t filename_len;
path_len = ES_strlen(path);
filename_len = ES_strlen(filename);
return path_len >= filename_len + 1
&& path[path_len - filename_len - 1] == DIR_SEPARATOR
&& !ES_strcasecmp(&path[path_len - filename_len], filename);
}
// Check if the specified directory contains the specified IWAD
// file, returning the full path to the IWAD if found, or NULL
// if not found.
static char *CheckDirectoryHasIWAD(char *dir, char *iwadname)
{
char *filename;
// As a special case, the "directory" may refer directly to an
// IWAD file if the path comes from DOOMWADDIR or DOOMWADPATH.
if (DirIsFile(dir, iwadname) && M_FileExists(dir))
{
return ES_strdup(dir);
}
// Construct the full path to the IWAD if it is located in
// this directory, and check if it exists.
if (!ES_strcmp(dir, "."))
{
filename = ES_strdup(iwadname);
}
else
{
filename = M_StringJoin(dir, DIR_SEPARATOR_S, iwadname, NULL);
}
ES_debugf("Trying IWAD file:%s\n", filename);
if (M_FileExists(filename))
{
return filename;
}
ES_free(filename);
return NULL;
}
// Search a directory to try to find an IWAD
// Returns the location of the IWAD if found, otherwise NULL.
static char *SearchDirectoryForIWAD(char *dir, int mask, GameMission_t *mission)
{
char *filename;
size_t i;
for (i=0; i<arrlen(iwads); ++i)
{
if (((1 << iwads[i].mission) & mask) == 0)
{
continue;
}
filename = CheckDirectoryHasIWAD(dir, iwads[i].name);
if (filename != NULL)
{
*mission = iwads[i].mission;
return filename;
}
}
return NULL;
}
// When given an IWAD with the '-iwad' parameter,
// attempt to identify it by its name.
static GameMission_t IdentifyIWADByName(char *name, int mask)
{
size_t i;
GameMission_t mission;
char *p;
p = ES_strchr(name, DIR_SEPARATOR);
if (p != NULL)
{
name = p + 1;
}
mission = none;
for (i=0; i<arrlen(iwads); ++i)
{
// Check if the filename is this IWAD name.
// Only use supported missions:
if (((1 << iwads[i].mission) & mask) == 0)
continue;
// Check if it ends in this IWAD name.
if (!ES_strcasecmp(name, iwads[i].name))
{
mission = iwads[i].mission;
break;
}
}
return mission;
}
//
// Build a list of IWAD files
//
static void BuildIWADDirList(void)
{
AddIWADDir (FILES_DIR);
// Don't run this function again.
iwad_dirs_built = true;
}
//
// Searches WAD search paths for an WAD with a specific filename.
//
char *D_FindWADByName(char *name)
{
char *path;
int i;
// Absolute path?
if (M_FileExists(name))
{
return name;
}
BuildIWADDirList();
// Search through all IWAD paths for a file with the given name.
for (i=0; i<num_iwad_dirs; ++i)
{
// As a special case, if this is in DOOMWADDIR or DOOMWADPATH,
// the "directory" may actually refer directly to an IWAD
// file.
if (DirIsFile(iwad_dirs[i], name) && M_FileExists(iwad_dirs[i]))
{
return ES_strdup(iwad_dirs[i]);
}
// Construct a string for the full path
path = M_StringJoin(iwad_dirs[i], DIR_SEPARATOR_S, name, NULL);
if (M_FileExists(path))
{
return path;
}
ES_free(path);
}
// File not found
return NULL;
}
//
// D_TryWADByName
//
// Searches for a WAD by its filename, or passes through the filename
// if not found.
//
char *D_TryFindWADByName(char *filename)
{
char *result;
result = D_FindWADByName(filename);
if (result != NULL)
{
return result;
}
else
{
return filename;
}
}
//
// FindIWAD
// Checks availability of IWAD files by name,
// to determine whether registered/commercial features
// should be executed (notably loading PWADs).
//
char *D_FindIWAD(int mask, GameMission_t *mission)
{
char *result;
char *iwadfile;
int iwadparm;
int i;
// Check for the -iwad parameter
//!
// Specify an IWAD file to use.
//
// @arg <file>
//
iwadparm = M_CheckParmWithArgs("-iwad", 1);
if (iwadparm)
{
// Search through IWAD dirs for an IWAD with the given name.
iwadfile = myargv[iwadparm + 1];
result = D_FindWADByName(iwadfile);
if (result == NULL)
{
I_Error("IWAD file '%s' not found!", iwadfile);
}
*mission = IdentifyIWADByName(result, mask);
}
else
{
// Search through the list and look for an IWAD
ES_debugf("-iwad not specified, trying a few iwad names\n");
result = NULL;
BuildIWADDirList();
for (i=0; result == NULL && i<num_iwad_dirs; ++i)
{
result = SearchDirectoryForIWAD(iwad_dirs[i], mask, mission);
}
}
return result;
}
// Find all IWADs in the IWAD search path matching the given mask.
const iwad_t **D_FindAllIWADs(int mask)
{
const iwad_t **result;
int result_len;
char *filename;
size_t i;
result = ES_malloc(sizeof(iwad_t *) * (arrlen(iwads) + 1));
result_len = 0;
// Try to find all IWADs
for (i=0; i<arrlen(iwads); ++i)
{
if (((1 << iwads[i].mission) & mask) == 0)
{
continue;
}
filename = D_FindWADByName(iwads[i].name);
if (filename != NULL)
{
result[result_len] = &iwads[i];
++result_len;
}
}
// End of list
result[result_len] = NULL;
return result;
}
//
// Get the IWAD name used for savegames.
//
char *D_SaveGameIWADName(GameMission_t gamemission)
{
size_t i;
// Determine the IWAD name to use for savegames.
// This determines the directory the savegame files get put into.
//
// Note that we match on gamemission rather than on IWAD name.
// This ensures that doom1.wad and doom.wad saves are stored
// in the same place.
for (i=0; i<arrlen(iwads); ++i)
{
if (gamemission == iwads[i].mission)
{
return iwads[i].name;
}
}
// Default fallback:
return "unknown.wad";
}
char *D_SuggestIWADName(GameMission_t mission, GameMode_t mode)
{
size_t i;
for (i = 0; i < arrlen(iwads); ++i)
{
if (iwads[i].mission == mission && iwads[i].mode == mode)
{
return iwads[i].name;
}
}
return "unknown.wad";
}
char *D_SuggestGameName(GameMission_t mission, GameMode_t mode)
{
for (size_t i = 0; i < arrlen(iwads); ++i)
{
if (iwads[i].mission == mission
&& (mode == indetermined || iwads[i].mode == mode))
{
return iwads[i].description;
}
}
return "Unknown game?";
}

52
apps/doom/d_iwad.h Normal file
View File

@ -0,0 +1,52 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Find IWAD and initialize according to IWAD type.
//
#ifndef __D_IWAD__
#define __D_IWAD__
#include "d_mode.h"
#define IWAD_MASK_DOOM ((1 << doom) \
| (1 << doom2) \
| (1 << pack_tnt) \
| (1 << pack_plut) \
| (1 << pack_chex) \
| (1 << pack_hacx))
#define IWAD_MASK_HERETIC (1 << heretic)
#define IWAD_MASK_HEXEN (1 << hexen)
#define IWAD_MASK_STRIFE (1 << strife)
typedef struct
{
char *name;
GameMission_t mission;
GameMode_t mode;
char *description;
} iwad_t;
char *D_FindWADByName(char *filename);
char *D_TryFindWADByName(char *filename);
char *D_FindIWAD(int mask, GameMission_t *mission);
const iwad_t **D_FindAllIWADs(int mask);
char *D_SaveGameIWADName(GameMission_t gamemission);
char *D_SuggestIWADName(GameMission_t mission, GameMode_t mode);
char *D_SuggestGameName(GameMission_t mission, GameMode_t mode);
void D_CheckCorrectIWAD(GameMission_t mission);
#endif

687
apps/doom/d_loop.c Normal file
View File

@ -0,0 +1,687 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Main loop code.
//
#include "essence/include.h"
#include "config.h"
#include "d_event.h"
#include "d_loop.h"
#include "d_ticcmd.h"
#include "i_system.h"
#include "i_timer.h"
#include "i_video.h"
#include "m_argv.h"
#include "m_fixed.h"
#include "net_client.h"
#include "net_gui.h"
#include "net_io.h"
#include "net_query.h"
#include "net_server.h"
#include "net_loop.h"
// The complete set of data for a particular tic.
typedef struct
{
ticcmd_t cmds[NET_MAXPLAYERS];
boolean ingame[NET_MAXPLAYERS];
} ticcmd_set_t;
//
// gametic is the tic about to (or currently being) run
// maketic is the tic that hasn't had control made for it yet
// recvtic is the latest tic received from the server.
//
// a gametic cannot be run until ticcmds are received for it
// from all players.
//
static ticcmd_set_t ticdata[BACKUPTICS];
// The index of the next tic to be made (with a call to BuildTiccmd).
static int maketic;
// The number of complete tics received from the server so far.
static int recvtic;
// The number of tics that have been run (using RunTic) so far.
int gametic;
// When set to true, a single tic is run each time TryRunTics() is called.
// This is used for -timedemo mode.
boolean singletics = false;
// Index of the local player.
static int localplayer;
// Used for original sync code.
static int skiptics = 0;
// Reduce the bandwidth needed by sampling game input less and transmitting
// less. If ticdup is 2, sample half normal, 3 = one third normal, etc.
int ticdup;
// Amount to offset the timer for game sync.
fixed_t offsetms;
// Use new client syncronisation code
static boolean new_sync = true;
// Callback functions for loop code.
static loop_interface_t *loop_interface = NULL;
// Current players in the multiplayer game.
// This is distinct from playeringame[] used by the game code, which may
// modify playeringame[] when playing back multiplayer demos.
static boolean local_playeringame[NET_MAXPLAYERS];
// Requested player class "sent" to the server on connect.
// If we are only doing a single player game then this needs to be remembered
// and saved in the game settings.
static int player_class;
// 35 fps clock adjusted by offsetms milliseconds
static int GetAdjustedTime(void)
{
int time_ms;
time_ms = I_GetTimeMS();
if (new_sync)
{
// Use the adjustments from net_client.c only if we are
// using the new sync mode.
time_ms += (offsetms / FRACUNIT);
}
return (time_ms * TICRATE) / 1000;
}
static boolean BuildNewTic(void)
{
int gameticdiv;
ticcmd_t cmd;
gameticdiv = gametic/ticdup;
I_StartTic ();
loop_interface->ProcessEvents();
// Always run the menu
loop_interface->RunMenu();
if (drone)
{
// In drone mode, do not generate any ticcmds.
return false;
}
if (new_sync)
{
// If playing single player, do not allow tics to buffer
// up very far
if (!net_client_connected && maketic - gameticdiv > 2)
return false;
// Never go more than ~200ms ahead
if (maketic - gameticdiv > 8)
return false;
}
else
{
if (maketic - gameticdiv >= 5)
return false;
}
ES_memset(&cmd, 0, sizeof(ticcmd_t));
loop_interface->BuildTiccmd(&cmd, maketic);
#ifdef FEATURE_MULTIPLAYER
if (net_client_connected)
{
NET_CL_SendTiccmd(&cmd, maketic);
}
#endif
ticdata[maketic % BACKUPTICS].cmds[localplayer] = cmd;
ticdata[maketic % BACKUPTICS].ingame[localplayer] = true;
++maketic;
return true;
}
//
// NetUpdate
// Builds ticcmds for console player,
// sends out a packet
//
int lasttime;
void NetUpdate (void)
{
int nowtime;
int newtics;
int i;
// If we are running with singletics (timing a demo), this
// is all done separately.
if (singletics)
return;
#ifdef FEATURE_MULTIPLAYER
// Run network subsystems
NET_CL_Run();
NET_SV_Run();
#endif
// check time
nowtime = GetAdjustedTime() / ticdup;
newtics = nowtime - lasttime;
lasttime = nowtime;
if (skiptics <= newtics)
{
newtics -= skiptics;
skiptics = 0;
}
else
{
skiptics -= newtics;
newtics = 0;
}
// build new ticcmds for console player
for (i=0 ; i < newtics; i++)
{
if (!BuildNewTic())
{
break;
}
}
}
static void D_Disconnected(void)
{
// In drone mode, the game cannot continue once disconnected.
if (drone)
{
I_Error("Disconnected from server in drone mode.");
}
// disconnected from server
ES_debugf("Disconnected from server.\n");
}
//
// Invoked by the network engine when a complete set of ticcmds is
// available.
//
void D_ReceiveTic(ticcmd_t *ticcmds, boolean *players_mask)
{
size_t i;
// Disconnected from server?
if (ticcmds == NULL && players_mask == NULL)
{
D_Disconnected();
return;
}
for (i = 0; i < NET_MAXPLAYERS; ++i)
{
if (!drone && i == localplayer)
{
// This is us. Don't overwrite it.
}
else
{
ticdata[recvtic % BACKUPTICS].cmds[i] = ticcmds[i];
ticdata[recvtic % BACKUPTICS].ingame[i] = players_mask[i];
}
}
++recvtic;
}
//
// Start game loop
//
// Called after the screen is set but before the game starts running.
//
void D_StartGameLoop(void)
{
lasttime = GetAdjustedTime() / ticdup;
}
void D_StartNetGame(net_gamesettings_t *settings,
netgame_startup_callback_t callback)
{
settings->consoleplayer = 0;
settings->num_players = 1;
settings->player_classes[0] = player_class;
settings->new_sync = 0;
settings->extratics = 1;
settings->ticdup = 1;
ticdup = settings->ticdup;
new_sync = settings->new_sync;
}
boolean D_InitNetGame(net_connect_data_t *connect_data)
{
boolean result = false;
#ifdef FEATURE_MULTIPLAYER
net_addr_t *addr = NULL;
int i;
#endif
// Call D_QuitNetGame on exit:
I_AtExit(D_QuitNetGame, true);
player_class = connect_data->player_class;
#ifdef FEATURE_MULTIPLAYER
//!
// @category net
//
// Start a multiplayer server, listening for connections.
//
if (M_CheckParm("-server") > 0
|| M_CheckParm("-privateserver") > 0)
{
NET_SV_Init();
NET_SV_AddModule(&net_loop_server_module);
NET_SV_AddModule(&net_sdl_module);
NET_SV_RegisterWithMaster();
net_loop_client_module.InitClient();
addr = net_loop_client_module.ResolveAddress(NULL);
}
else
{
//!
// @category net
//
// Automatically search the local LAN for a multiplayer
// server and join it.
//
i = M_CheckParm("-autojoin");
if (i > 0)
{
addr = NET_FindLANServer();
if (addr == NULL)
{
I_Error("No server found on local LAN");
}
}
//!
// @arg <address>
// @category net
//
// Connect to a multiplayer server running on the given
// address.
//
i = M_CheckParmWithArgs("-connect", 1);
if (i > 0)
{
net_sdl_module.InitClient();
addr = net_sdl_module.ResolveAddress(myargv[i+1]);
if (addr == NULL)
{
I_Error("Unable to resolve '%s'\n", myargv[i+1]);
}
}
}
if (addr != NULL)
{
if (M_CheckParm("-drone") > 0)
{
connect_data->drone = true;
}
if (!NET_CL_Connect(addr, connect_data))
{
I_Error("D_InitNetGame: Failed to connect to %s\n",
NET_AddrToString(addr));
}
ES_debuf("D_InitNetGame: Connected to %s\n", NET_AddrToString(addr));
// Wait for launch message received from server.
NET_WaitForLaunch();
result = true;
}
#endif
return result;
}
//
// D_QuitNetGame
// Called before quitting to leave a net game
// without hanging the other players
//
void D_QuitNetGame (void)
{
#ifdef FEATURE_MULTIPLAYER
NET_SV_Shutdown();
NET_CL_Disconnect();
#endif
}
static int GetLowTic(void)
{
int lowtic;
lowtic = maketic;
#ifdef FEATURE_MULTIPLAYER
if (net_client_connected)
{
if (drone || recvtic < lowtic)
{
lowtic = recvtic;
}
}
#endif
return lowtic;
}
static int frameon;
static int frameskip[4];
static int oldnettics;
static void OldNetSync(void)
{
unsigned int i;
int keyplayer = -1;
frameon++;
// ideally maketic should be 1 - 3 tics above lowtic
// if we are consistantly slower, speed up time
for (i=0 ; i<NET_MAXPLAYERS ; i++)
{
if (local_playeringame[i])
{
keyplayer = i;
break;
}
}
if (keyplayer < 0)
{
// If there are no players, we can never advance anyway
return;
}
if (localplayer == keyplayer)
{
// the key player does not adapt
}
else
{
if (maketic <= recvtic)
{
lasttime--;
}
frameskip[frameon & 3] = oldnettics > recvtic;
oldnettics = maketic;
if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
{
skiptics = 1;
}
}
}
// Returns true if there are players in the game:
static boolean PlayersInGame(void)
{
boolean result = false;
unsigned int i;
// If we are connected to a server, check if there are any players
// in the game.
if (net_client_connected)
{
for (i = 0; i < NET_MAXPLAYERS; ++i)
{
result = result || local_playeringame[i];
}
}
// Whether single or multi-player, unless we are running as a drone,
// we are in the game.
if (!drone)
{
result = true;
}
return result;
}
// When using ticdup, certain values must be cleared out when running
// the duplicate ticcmds.
static void TicdupSquash(ticcmd_set_t *set)
{
ticcmd_t *cmd;
unsigned int i;
for (i = 0; i < NET_MAXPLAYERS ; ++i)
{
cmd = &set->cmds[i];
cmd->chatchar = 0;
if (cmd->buttons & BT_SPECIAL)
cmd->buttons = 0;
}
}
// When running in single player mode, clear all the ingame[] array
// except the local player.
static void SinglePlayerClear(ticcmd_set_t *set)
{
unsigned int i;
for (i = 0; i < NET_MAXPLAYERS; ++i)
{
if (i != localplayer)
{
set->ingame[i] = false;
}
}
}
//
// TryRunTics
//
void TryRunTics (void)
{
int i;
int lowtic;
int entertic;
static int oldentertics;
int realtics;
int availabletics;
int counts;
// get real tics
entertic = I_GetTime() / ticdup;
realtics = entertic - oldentertics;
oldentertics = entertic;
// in singletics mode, run a single tic every time this function
// is called.
if (singletics)
{
BuildNewTic();
}
else
{
NetUpdate();
}
lowtic = GetLowTic();
availabletics = lowtic - gametic/ticdup;
// decide how many tics to run
if (new_sync)
{
counts = availabletics;
}
else
{
// decide how many tics to run
if (realtics < availabletics-1)
counts = realtics+1;
else if (realtics < availabletics)
counts = realtics;
else
counts = availabletics;
if (counts < 1)
counts = 1;
if (net_client_connected)
{
OldNetSync();
}
}
if (counts < 1) counts = 1;
// wait for new tics if needed
while (!PlayersInGame() || lowtic < gametic/ticdup + counts)
{
NetUpdate();
lowtic = GetLowTic();
if (lowtic < gametic/ticdup) I_Error("TryRunTics: lowtic < gametic");
// Don't stay in this loop forever. The menu is still running,
// so return to update the screen
if (I_GetTime() / ticdup - entertic > 0)
{
return;
}
I_Sleep(1);
}
// run the count * ticdup dics
while (counts--)
{
ticcmd_set_t *set;
if (!PlayersInGame())
{
return;
}
set = &ticdata[(gametic / ticdup) % BACKUPTICS];
if (!net_client_connected)
{
SinglePlayerClear(set);
}
for (i=0; i<ticdup; i++)
{
if (gametic/ticdup > lowtic) I_Error ("gametic>lowtic");
ES_memcpy(local_playeringame, set->ingame, sizeof(local_playeringame));
loop_interface->RunTic(set->cmds, set->ingame);
gametic++;
// modify command for duplicated tics
TicdupSquash(set);
}
NetUpdate(); // check for new console commands
}
}
void D_RegisterLoopCallbacks(loop_interface_t *i)
{
loop_interface = i;
}

81
apps/doom/d_loop.h Normal file
View File

@ -0,0 +1,81 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Main loop stuff.
//
#ifndef __D_LOOP__
#define __D_LOOP__
#include "net_defs.h"
// Callback function invoked while waiting for the netgame to start.
// The callback is invoked when new players are ready. The callback
// should return true, or return false to abort startup.
typedef boolean (*netgame_startup_callback_t)(int ready_players,
int num_players);
typedef struct
{
// Read events from the event queue, and process them.
void (*ProcessEvents)();
// Given the current input state, fill in the fields of the specified
// ticcmd_t structure with data for a new tic.
void (*BuildTiccmd)(ticcmd_t *cmd, int maketic);
// Advance the game forward one tic, using the specified player input.
void (*RunTic)(ticcmd_t *cmds, boolean *ingame);
// Run the menu (runs independently of the game).
void (*RunMenu)();
} loop_interface_t;
// Register callback functions for the main loop code to use.
void D_RegisterLoopCallbacks(loop_interface_t *i);
// Create any new ticcmds and broadcast to other players.
void NetUpdate (void);
// Broadcasts special packets to other players
// to notify of game exit
void D_QuitNetGame (void);
//? how many ticks to run?
void TryRunTics (void);
// Called at start of game loop to initialize timers
void D_StartGameLoop(void);
// Initialize networking code and connect to server.
boolean D_InitNetGame(net_connect_data_t *connect_data);
// Start game with specified settings. The structure will be updated
// with the actual settings for the game.
void D_StartNetGame(net_gamesettings_t *settings,
netgame_startup_callback_t callback);
extern boolean singletics;
extern int gametic, ticdup;
#endif

1487
apps/doom/d_main.c Normal file

File diff suppressed because it is too large Load Diff

47
apps/doom/d_main.h Normal file
View File

@ -0,0 +1,47 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// System specific interface stuff.
//
#ifndef __D_MAIN__
#define __D_MAIN__
#include "doomdef.h"
// Read events from all input devices
void D_ProcessEvents (void);
//
// BASE LEVEL
//
void D_PageTicker (void);
void D_PageDrawer (void);
void D_AdvanceDemo (void);
void D_DoAdvanceDemo (void);
void D_StartTitle (void);
void D_DoomMain (void);
void D_DoomTick (void);
//
// GLOBAL VARIABLES
//
extern gameaction_t gameaction;
#endif

208
apps/doom/d_mode.c Normal file
View File

@ -0,0 +1,208 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// DESCRIPTION:
// Functions and definitions relating to the game type and operational
// mode.
//
#include "doomtype.h"
#include "d_mode.h"
// Valid game mode/mission combinations, with the number of
// episodes/maps for each.
static struct
{
GameMission_t mission;
GameMode_t mode;
int episode;
int map;
} valid_modes[] = {
{ pack_chex, shareware, 1, 5 },
{ doom, shareware, 1, 9 },
{ doom, registered, 3, 9 },
{ doom, retail, 4, 9 },
{ doom2, commercial, 1, 32 },
{ pack_tnt, commercial, 1, 32 },
{ pack_plut, commercial, 1, 32 },
{ pack_hacx, commercial, 1, 32 },
{ heretic, shareware, 1, 9 },
{ heretic, registered, 3, 9 },
{ heretic, retail, 5, 9 },
{ hexen, commercial, 1, 60 },
{ strife, commercial, 1, 34 },
};
// Check that a gamemode+gamemission received over the network is valid.
boolean D_ValidGameMode(GameMission_t mission, GameMode_t mode)
{
size_t i;
for (i=0; i<arrlen(valid_modes); ++i)
{
if (valid_modes[i].mode == mode && valid_modes[i].mission == mission)
{
return true;
}
}
return false;
}
boolean D_ValidEpisodeMap(GameMission_t mission, GameMode_t mode,
int episode, int map)
{
int i;
// Hacks for Heretic secret episodes
if (mission == heretic)
{
if (mode == retail && episode == 6)
{
return map >= 1 && map <= 3;
}
else if (mode == registered && episode == 4)
{
return map == 1;
}
}
// Find the table entry for this mission/mode combination.
for (i=0; i<arrlen(valid_modes); ++i)
{
if (mission == valid_modes[i].mission
&& mode == valid_modes[i].mode)
{
return episode >= 1 && episode <= valid_modes[i].episode
&& map >= 1 && map <= valid_modes[i].map;
}
}
// Unknown mode/mission combination
return false;
}
// Get the number of valid episodes for the specified mission/mode.
int D_GetNumEpisodes(GameMission_t mission, GameMode_t mode)
{
int episode;
episode = 1;
while (D_ValidEpisodeMap(mission, mode, episode, 1))
{
++episode;
}
return episode - 1;
}
// Table of valid versions
static struct {
GameMission_t mission;
GameVersion_t version;
} valid_versions[] = {
{ doom, exe_doom_1_9 },
{ doom, exe_hacx },
{ doom, exe_ultimate },
{ doom, exe_final },
{ doom, exe_final2 },
{ doom, exe_chex },
{ heretic, exe_heretic_1_3 },
{ hexen, exe_hexen_1_1 },
{ strife, exe_strife_1_2 },
{ strife, exe_strife_1_31 },
};
boolean D_ValidGameVersion(GameMission_t mission, GameVersion_t version)
{
size_t i;
// All Doom variants can use the Doom versions.
if (mission == doom2 || mission == pack_plut || mission == pack_tnt
|| mission == pack_hacx || mission == pack_chex)
{
mission = doom;
}
for (i=0; i<arrlen(valid_versions); ++i)
{
if (valid_versions[i].mission == mission
&& valid_versions[i].version == version)
{
return true;
}
}
return false;
}
// Does this mission type use ExMy form, rather than MAPxy form?
boolean D_IsEpisodeMap(GameMission_t mission)
{
switch (mission)
{
case doom:
case heretic:
case pack_chex:
return true;
case none:
case hexen:
case doom2:
case pack_hacx:
case pack_tnt:
case pack_plut:
case strife:
default:
return false;
}
}
char *D_GameMissionString(GameMission_t mission)
{
switch (mission)
{
case none:
default:
return "none";
case doom:
return "doom";
case doom2:
return "doom2";
case pack_tnt:
return "tnt";
case pack_plut:
return "plutonia";
case pack_hacx:
return "hacx";
case pack_chex:
return "chex";
case heretic:
return "heretic";
case hexen:
return "hexen";
case strife:
return "strife";
}
}

97
apps/doom/d_mode.h Normal file
View File

@ -0,0 +1,97 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Functions and definitions relating to the game type and operational
// mode.
//
#ifndef __D_MODE__
#define __D_MODE__
#include "doomtype.h"
// The "mission" controls what game we are playing.
typedef enum
{
doom, // Doom 1
doom2, // Doom 2
pack_tnt, // Final Doom: TNT: Evilution
pack_plut, // Final Doom: The Plutonia Experiment
pack_chex, // Chex Quest (modded doom)
pack_hacx, // Hacx (modded doom2)
heretic, // Heretic
hexen, // Hexen
strife, // Strife
none
} GameMission_t;
// The "mode" allows more accurate specification of the game mode we are
// in: eg. shareware vs. registered. So doom1.wad and doom.wad are the
// same mission, but a different mode.
typedef enum
{
shareware, // Doom/Heretic shareware
registered, // Doom/Heretic registered
commercial, // Doom II/Hexen
retail, // Ultimate Doom
indetermined // Unknown.
} GameMode_t;
// What version are we emulating?
typedef enum
{
exe_doom_1_2, // Doom 1.2: shareware and registered
exe_doom_1_666, // Doom 1.666: for shareware, registered and commercial
exe_doom_1_7, // Doom 1.7/1.7a: "
exe_doom_1_8, // Doom 1.8: "
exe_doom_1_9, // Doom 1.9: "
exe_hacx, // Hacx
exe_ultimate, // Ultimate Doom (retail)
exe_final, // Final Doom
exe_final2, // Final Doom (alternate exe)
exe_chex, // Chex Quest executable (based on Final Doom)
exe_heretic_1_3, // Heretic 1.3
exe_hexen_1_1, // Hexen 1.1
exe_strife_1_2, // Strife v1.2
exe_strife_1_31 // Strife v1.31
} GameVersion_t;
// Skill level.
typedef enum
{
sk_noitems = -1, // the "-skill 0" hack
sk_baby = 0,
sk_easy,
sk_medium,
sk_hard,
sk_nightmare
} skill_t;
boolean D_ValidGameMode(GameMission_t mission, GameMode_t mode);
boolean D_ValidGameVersion(GameMission_t mission, GameVersion_t version);
boolean D_ValidEpisodeMap(GameMission_t mission, GameMode_t mode,
int episode, int map);
int D_GetNumEpisodes(GameMission_t mission, GameMode_t mode);
boolean D_IsEpisodeMap(GameMission_t mission);
char *D_GameMissionString(GameMission_t mission);
#endif /* #ifndef __D_MODE__ */

271
apps/doom/d_net.c Normal file
View File

@ -0,0 +1,271 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// DOOM Network game communication and protocol,
// all OS independend parts.
//
#include "essence/include.h"
#include "config.h"
#include "d_main.h"
#include "m_argv.h"
#include "m_menu.h"
#include "m_misc.h"
#include "i_system.h"
#include "i_timer.h"
#include "i_video.h"
#include "g_game.h"
#include "doomdef.h"
#include "doomstat.h"
#include "w_checksum.h"
#include "w_wad.h"
#include "d_loop.h"
ticcmd_t *netcmds;
// Called when a player leaves the game
static void PlayerQuitGame(player_t *player)
{
static char exitmsg[80];
unsigned int player_num;
player_num = player - players;
// Do this the same way as Vanilla Doom does, to allow dehacked
// replacements of this message
M_StringCopy(exitmsg, "Player 1 left the game",
sizeof(exitmsg));
exitmsg[7] += player_num;
playeringame[player_num] = false;
players[consoleplayer].message = exitmsg;
// TODO: check if it is sensible to do this:
if (demorecording)
{
G_CheckDemoStatus ();
}
}
static void RunTic(ticcmd_t *cmds, boolean *ingame)
{
extern boolean advancedemo;
unsigned int i;
// Check for player quits.
for (i = 0; i < MAXPLAYERS; ++i)
{
if (!demoplayback && playeringame[i] && !ingame[i])
{
PlayerQuitGame(&players[i]);
}
}
netcmds = cmds;
// check that there are players in the game. if not, we cannot
// run a tic.
if (advancedemo)
D_DoAdvanceDemo ();
G_Ticker ();
}
static loop_interface_t doom_loop_interface = {
D_ProcessEvents,
G_BuildTiccmd,
RunTic,
M_Ticker
};
// Load game settings from the specified structure and
// set global variables.
static void LoadGameSettings(net_gamesettings_t *settings)
{
unsigned int i;
deathmatch = settings->deathmatch;
startepisode = settings->episode;
startmap = settings->map;
startskill = settings->skill;
startloadgame = settings->loadgame;
lowres_turn = settings->lowres_turn;
nomonsters = settings->nomonsters;
fastparm = settings->fast_monsters;
respawnparm = settings->respawn_monsters;
timelimit = settings->timelimit;
consoleplayer = settings->consoleplayer;
if (lowres_turn)
{
ES_infof("Turning resolution is reduced; this is probably "
"because there is a client recording a Vanilla demo.\n");
}
for (i = 0; i < MAXPLAYERS; ++i)
{
playeringame[i] = i < settings->num_players;
}
}
// Save the game settings from global variables to the specified
// game settings structure.
static void SaveGameSettings(net_gamesettings_t *settings)
{
// Fill in game settings structure with appropriate parameters
// for the new game
settings->deathmatch = deathmatch;
settings->episode = startepisode;
settings->map = startmap;
settings->skill = startskill;
settings->loadgame = startloadgame;
settings->gameversion = gameversion;
settings->nomonsters = nomonsters;
settings->fast_monsters = fastparm;
settings->respawn_monsters = respawnparm;
settings->timelimit = timelimit;
settings->lowres_turn = M_CheckParm("-record") > 0
&& M_CheckParm("-longtics") == 0;
}
static void InitConnectData(net_connect_data_t *connect_data)
{
connect_data->max_players = MAXPLAYERS;
connect_data->drone = false;
//!
// @category net
//
// Run as the left screen in three screen mode.
//
if (M_CheckParm("-left") > 0)
{
viewangleoffset = ANG90;
connect_data->drone = true;
}
//!
// @category net
//
// Run as the right screen in three screen mode.
//
if (M_CheckParm("-right") > 0)
{
viewangleoffset = ANG270;
connect_data->drone = true;
}
//
// Connect data
//
// Game type fields:
connect_data->gamemode = gamemode;
connect_data->gamemission = gamemission;
// Are we recording a demo? Possibly set lowres turn mode
connect_data->lowres_turn = M_CheckParm("-record") > 0
&& M_CheckParm("-longtics") == 0;
// Read checksums of our WAD directory and dehacked information
W_Checksum(connect_data->wad_sha1sum);
// Are we playing with the Freedoom IWAD?
connect_data->is_freedoom = W_CheckNumForName("FREEDOOM") >= 0;
}
void D_ConnectNetGame(void)
{
net_connect_data_t connect_data;
InitConnectData(&connect_data);
netgame = D_InitNetGame(&connect_data);
//!
// @category net
//
// Start the game playing as though in a netgame with a single
// player. This can also be used to play back single player netgame
// demos.
//
if (M_CheckParm("-solo-net") > 0)
{
netgame = true;
}
}
//
// D_CheckNetGame
// Works out player numbers among the net participants
//
void D_CheckNetGame (void)
{
net_gamesettings_t settings;
if (netgame)
{
autostart = true;
}
D_RegisterLoopCallbacks(&doom_loop_interface);
SaveGameSettings(&settings);
D_StartNetGame(&settings, NULL);
LoadGameSettings(&settings);
ES_debugf("startskill %i deathmatch: %i startmap: %i startepisode: %i\n",
startskill, deathmatch, startmap, startepisode);
ES_debugf("player %i of %i (%i nodes)\n",
consoleplayer+1, settings.num_players, settings.num_players);
// Show players here; the server might have specified a time limit
if (timelimit > 0 && deathmatch)
{
// Gross hack to work like Vanilla:
if (timelimit == 20 && M_CheckParm("-avg"))
{
ES_debugf("Austin Virtual Gaming: Levels will end "
"after 20 minutes\n");
}
else
{
ES_debugf("Levels will end after %d minute%.2s.\n", timelimit, (timelimit > 1) ? "s" : "");
}
}
}

200
apps/doom/d_player.h Normal file
View File

@ -0,0 +1,200 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
//
//
#ifndef __D_PLAYER__
#define __D_PLAYER__
// The player data structure depends on a number
// of other structs: items (internal inventory),
// animation states (closely tied to the sprites
// used to represent them, unfortunately).
#include "d_items.h"
#include "p_pspr.h"
// In addition, the player is just a special
// case of the generic moving object/actor.
#include "p_mobj.h"
// Finally, for odd reasons, the player input
// is buffered within the player data struct,
// as commands per game tick.
#include "d_ticcmd.h"
#include "net_defs.h"
//
// Player states.
//
typedef enum
{
// Playing or camping.
PST_LIVE,
// Dead on the ground, view follows killer.
PST_DEAD,
// Ready to restart/respawn???
PST_REBORN
} playerstate_t;
//
// Player internal flags, for cheats and debug.
//
typedef enum
{
// No clipping, walk through barriers.
CF_NOCLIP = 1,
// No damage, no health loss.
CF_GODMODE = 2,
// Not really a cheat, just a debug aid.
CF_NOMOMENTUM = 4
} cheat_t;
//
// Extended player object info: player_t
//
typedef struct player_s
{
mobj_t* mo;
playerstate_t playerstate;
ticcmd_t cmd;
// Determine POV,
// including viewpoint bobbing during movement.
// Focal origin above r.z
fixed_t viewz;
// Base height above floor for viewz.
fixed_t viewheight;
// Bob/squat speed.
fixed_t deltaviewheight;
// bounded/scaled total momentum.
fixed_t bob;
// This is only used between levels,
// mo->health is used during levels.
int health;
int armorpoints;
// Armor type is 0-2.
int armortype;
// Power ups. invinc and invis are tic counters.
int powers[NUMPOWERS];
boolean cards[NUMCARDS];
boolean backpack;
// Frags, kills of other players.
int frags[MAXPLAYERS];
weapontype_t readyweapon;
// Is wp_nochange if not changing.
weapontype_t pendingweapon;
boolean weaponowned[NUMWEAPONS];
int ammo[NUMAMMO];
int maxammo[NUMAMMO];
// True if button down last tic.
int attackdown;
int usedown;
// Bit flags, for cheats and debug.
// See cheat_t, above.
int cheats;
// Refired shots are less accurate.
int refire;
// For intermission stats.
int killcount;
int itemcount;
int secretcount;
// Hint messages.
char* message;
// For screen flashing (red or bright).
int damagecount;
int bonuscount;
// Who did damage (NULL for floors/ceilings).
mobj_t* attacker;
// So gun flashes light up areas.
int extralight;
// Current PLAYPAL, ???
// can be set to REDCOLORMAP for pain, etc.
int fixedcolormap;
// Player skin colorshift,
// 0-3 for which color to draw player.
int colormap;
// Overlay view sprites (gun, etc).
pspdef_t psprites[NUMPSPRITES];
// True if secret level has been done.
boolean didsecret;
} player_t;
//
// INTERMISSION
// Structure passed e.g. to WI_Start(wb)
//
typedef struct
{
boolean in; // whether the player is in game
// Player stats, kills, collected items etc.
int skills;
int sitems;
int ssecret;
int stime;
int frags[4];
int score; // current score on entry, modified on return
} wbplayerstruct_t;
typedef struct
{
int epsd; // episode # (0-2)
// if true, splash the secret level
boolean didsecret;
// previous and next levels, origin 0
int last;
int next;
int maxkills;
int maxitems;
int maxsecret;
int maxfrags;
// the par time
int partime;
// index of this player in game
int pnum;
wbplayerstruct_t plyr[MAXPLAYERS];
} wbstartstruct_t;
#endif

37
apps/doom/d_textur.h Normal file
View File

@ -0,0 +1,37 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Typedefs related to to textures etc.,
// isolated here to make it easier separating modules.
//
#ifndef __D_TEXTUR__
#define __D_TEXTUR__
#include "doomtype.h"
//
// Flats?
//
// a pic is an unmasked block of pixels
typedef struct
{
byte width;
byte height;
byte data;
} pic_t;
#endif

56
apps/doom/d_think.h Normal file
View File

@ -0,0 +1,56 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// MapObj data. Map Objects or mobjs are actors, entities,
// thinker, take-your-pick... anything that moves, acts, or
// suffers state changes of more or less violent nature.
//
#ifndef __D_THINK__
#define __D_THINK__
//
// Experimental stuff.
// To compile this as "ANSI C with classes"
// we will need to handle the various
// action functions cleanly.
//
typedef void (*actionf_v)();
typedef void (*actionf_p1)( void* );
typedef void (*actionf_p2)( void*, void* );
typedef union
{
actionf_v acv;
actionf_p1 acp1;
actionf_p2 acp2;
} actionf_t;
// Historically, "think_t" is yet another
// function pointer to a routine to handle
// an actor.
typedef actionf_t think_t;
// Doubly linked list of actors.
typedef struct thinker_s
{
struct thinker_s* prev;
struct thinker_s* next;
think_t function;
} thinker_t;
#endif

52
apps/doom/d_ticcmd.h Normal file
View File

@ -0,0 +1,52 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 1993-2008 Raven Software
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// System specific interface stuff.
//
#ifndef __D_TICCMD__
#define __D_TICCMD__
#include "doomtype.h"
// The data sampled per tick (single player)
// and transmitted to other peers (multiplayer).
// Mainly movements/button commands per game tick,
// plus a checksum for internal state consistency.
typedef struct
{
signed char forwardmove; // *2048 for move
signed char sidemove; // *2048 for move
short angleturn; // <<16 for angle delta
byte chatchar;
byte buttons;
// villsa [STRIFE] according to the asm,
// consistancy is a short, not a byte
byte consistancy; // checks for net game
// villsa - Strife specific:
byte buttons2;
int inventory;
// Heretic/Hexen specific:
byte lookfly; // look/fly up/down/centering
byte arti; // artitype_t to use
} ticcmd_t;
#endif

196
apps/doom/doomdata.h Normal file
View File

@ -0,0 +1,196 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// all external data is defined here
// most of the data is loaded into different structures at run time
// some internal structures shared by many modules are here
//
#ifndef __DOOMDATA__
#define __DOOMDATA__
// The most basic types we use, portability.
#include "doomtype.h"
// Some global defines, that configure the game.
#include "doomdef.h"
//
// Map level types.
// The following data structures define the persistent format
// used in the lumps of the WAD files.
//
// Lump order in a map WAD: each map needs a couple of lumps
// to provide a complete scene geometry description.
enum
{
ML_LABEL, // A separator, name, ExMx or MAPxx
ML_THINGS, // Monsters, items..
ML_LINEDEFS, // LineDefs, from editing
ML_SIDEDEFS, // SideDefs, from editing
ML_VERTEXES, // Vertices, edited and BSP splits generated
ML_SEGS, // LineSegs, from LineDefs split by BSP
ML_SSECTORS, // SubSectors, list of LineSegs
ML_NODES, // BSP nodes
ML_SECTORS, // Sectors, from editing
ML_REJECT, // LUT, sector-sector visibility
ML_BLOCKMAP // LUT, motion clipping, walls/grid element
};
// A single Vertex.
typedef struct
{
short x;
short y;
} PACKEDATTR mapvertex_t;
// A SideDef, defining the visual appearance of a wall,
// by setting textures and offsets.
typedef struct
{
short textureoffset;
short rowoffset;
char toptexture[8];
char bottomtexture[8];
char midtexture[8];
// Front sector, towards viewer.
short sector;
} PACKEDATTR mapsidedef_t;
// A LineDef, as used for editing, and as input
// to the BSP builder.
typedef struct
{
short v1;
short v2;
short flags;
short special;
short tag;
// sidenum[1] will be -1 if one sided
short sidenum[2];
} PACKEDATTR maplinedef_t;
//
// LineDef attributes.
//
// Solid, is an obstacle.
#define ML_BLOCKING 1
// Blocks monsters only.
#define ML_BLOCKMONSTERS 2
// Backside will not be present at all
// if not two sided.
#define ML_TWOSIDED 4
// If a texture is pegged, the texture will have
// the end exposed to air held constant at the
// top or bottom of the texture (stairs or pulled
// down things) and will move with a height change
// of one of the neighbor sectors.
// Unpegged textures allways have the first row of
// the texture at the top pixel of the line for both
// top and bottom textures (use next to windows).
// upper texture unpegged
#define ML_DONTPEGTOP 8
// lower texture unpegged
#define ML_DONTPEGBOTTOM 16
// In AutoMap: don't map as two sided: IT'S A SECRET!
#define ML_SECRET 32
// Sound rendering: don't let sound cross two of these.
#define ML_SOUNDBLOCK 64
// Don't draw on the automap at all.
#define ML_DONTDRAW 128
// Set if already seen, thus drawn in automap.
#define ML_MAPPED 256
// Sector definition, from editing.
typedef struct
{
short floorheight;
short ceilingheight;
char floorpic[8];
char ceilingpic[8];
short lightlevel;
short special;
short tag;
} PACKEDATTR mapsector_t;
// SubSector, as generated by BSP.
typedef struct
{
short numsegs;
// Index of first one, segs are stored sequentially.
short firstseg;
} PACKEDATTR mapsubsector_t;
// LineSeg, generated by splitting LineDefs
// using partition lines selected by BSP builder.
typedef struct
{
short v1;
short v2;
short angle;
short linedef;
short side;
short offset;
} PACKEDATTR mapseg_t;
// BSP node structure.
// Indicate a leaf.
#define NF_SUBSECTOR 0x8000
typedef struct
{
// Partition line from (x,y) to x+dx,y+dy)
short x;
short y;
short dx;
short dy;
// Bounding box for each child,
// clip against view frustum.
short bbox[2][4];
// If NF_SUBSECTOR its a subsector,
// else it's a node of another subtree.
unsigned short children[2];
} PACKEDATTR mapnode_t;
// Thing definition, position, orientation and type,
// plus skill/visibility flags and attributes.
typedef struct
{
short x;
short y;
short angle;
short type;
short options;
} PACKEDATTR mapthing_t;
#endif // __DOOMDATA__

159
apps/doom/doomdef.h Normal file
View File

@ -0,0 +1,159 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Internally used data structures for virtually everything,
// lots of other stuff.
//
#ifndef __DOOMDEF__
#define __DOOMDEF__
#include "essence/include.h"
#include "doomtype.h"
#include "i_timer.h"
#include "d_mode.h"
//
// Global parameters/defines.
//
// DOOM version
#define DOOM_VERSION 109
// Version code for cph's longtics hack ("v1.91")
#define DOOM_191_VERSION 111
// If rangecheck is undefined,
// most parameter validation debugging code will not be compiled
#define RANGECHECK
// The maximum number of players, multiplayer/networking.
#define MAXPLAYERS 4
// The current state of the game: whether we are
// playing, gazing at the intermission screen,
// the game final animation, or a demo.
typedef enum
{
GS_LEVEL,
GS_INTERMISSION,
GS_FINALE,
GS_DEMOSCREEN,
} gamestate_t;
typedef enum
{
ga_nothing,
ga_loadlevel,
ga_newgame,
ga_loadgame,
ga_savegame,
ga_playdemo,
ga_completed,
ga_victory,
ga_worlddone,
ga_screenshot
} gameaction_t;
//
// Difficulty/skill settings/filters.
//
// Skill flags.
#define MTF_EASY 1
#define MTF_NORMAL 2
#define MTF_HARD 4
// Deaf monsters/do not react to sound.
#define MTF_AMBUSH 8
//
// Key cards.
//
typedef enum
{
it_bluecard,
it_yellowcard,
it_redcard,
it_blueskull,
it_yellowskull,
it_redskull,
NUMCARDS
} card_t;
// The defined weapons,
// including a marker indicating
// user has not changed weapon.
typedef enum
{
wp_fist,
wp_pistol,
wp_shotgun,
wp_chaingun,
wp_missile,
wp_plasma,
wp_bfg,
wp_chainsaw,
wp_supershotgun,
NUMWEAPONS,
// No pending weapon change.
wp_nochange
} weapontype_t;
// Ammunition types defined.
typedef enum
{
am_clip, // Pistol / chaingun ammo.
am_shell, // Shotgun / double barreled shotgun.
am_cell, // Plasma rifle, BFG.
am_misl, // Missile launcher.
NUMAMMO,
am_noammo // Unlimited for chainsaw / fist.
} ammotype_t;
// Power up artifacts.
typedef enum
{
pw_invulnerability,
pw_strength,
pw_invisibility,
pw_ironfeet,
pw_allmap,
pw_infrared,
NUMPOWERS
} powertype_t;
//
// Power up durations,
// how many seconds till expiration,
// assuming TICRATE is 35 ticks/second.
//
typedef enum
{
INVULNTICS = (30*TICRATE),
INVISTICS = (60*TICRATE),
INFRATICS = (120*TICRATE),
IRONTICS = (60*TICRATE)
} powerduration_t;
#endif // __DOOMDEF__

97
apps/doom/doomkeys.h Normal file
View File

@ -0,0 +1,97 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Key definitions
//
#ifndef __DOOMKEYS__
#define __DOOMKEYS__
//
// DOOM keyboard definition.
// This is the stuff configured by Setup.Exe.
// Most key data are simple ascii (uppercased).
//
#define KEY_RIGHTARROW 0xae
#define KEY_LEFTARROW 0xac
#define KEY_UPARROW 0xad
#define KEY_DOWNARROW 0xaf
#define KEY_STRAFE_L 0xa0
#define KEY_STRAFE_R 0xa1
#define KEY_USE 0xa2
#define KEY_FIRE 0xa3
#define KEY_ESCAPE 27
#define KEY_ENTER 13
#define KEY_TAB 9
#define KEY_F1 (0x80+0x3b)
#define KEY_F2 (0x80+0x3c)
#define KEY_F3 (0x80+0x3d)
#define KEY_F4 (0x80+0x3e)
#define KEY_F5 (0x80+0x3f)
#define KEY_F6 (0x80+0x40)
#define KEY_F7 (0x80+0x41)
#define KEY_F8 (0x80+0x42)
#define KEY_F9 (0x80+0x43)
#define KEY_F10 (0x80+0x44)
#define KEY_F11 (0x80+0x57)
#define KEY_F12 (0x80+0x58)
#define KEY_BACKSPACE 0x7f
#define KEY_PAUSE 0xff
#define KEY_EQUALS 0x3d
#define KEY_MINUS 0x2d
#define KEY_RSHIFT (0x80+0x36)
#define KEY_RCTRL (0x80+0x1d)
#define KEY_RALT (0x80+0x38)
#define KEY_LALT KEY_RALT
// new keys:
#define KEY_CAPSLOCK (0x80+0x3a)
#define KEY_NUMLOCK (0x80+0x45)
#define KEY_SCRLCK (0x80+0x46)
#define KEY_PRTSCR (0x80+0x59)
#define KEY_HOME (0x80+0x47)
#define KEY_END (0x80+0x4f)
#define KEY_PGUP (0x80+0x49)
#define KEY_PGDN (0x80+0x51)
#define KEY_INS (0x80+0x52)
#define KEY_DEL (0x80+0x53)
#define KEYP_0 0
#define KEYP_1 KEY_END
#define KEYP_2 KEY_DOWNARROW
#define KEYP_3 KEY_PGDN
#define KEYP_4 KEY_LEFTARROW
#define KEYP_5 '5'
#define KEYP_6 KEY_RIGHTARROW
#define KEYP_7 KEY_HOME
#define KEYP_8 KEY_UPARROW
#define KEYP_9 KEY_PGUP
#define KEYP_DIVIDE '/'
#define KEYP_PLUS '+'
#define KEYP_MINUS '-'
#define KEYP_MULTIPLY '*'
#define KEYP_PERIOD 0
#define KEYP_EQUALS KEY_EQUALS
#define KEYP_ENTER KEY_ENTER
#endif // __DOOMKEYS__

30
apps/doom/doomstat.c Normal file
View File

@ -0,0 +1,30 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Put all global tate variables here.
//
#include "essence/include.h"
#include "doomstat.h"
// Game Mode - identify IWAD as shareware, retail etc.
GameMode_t gamemode = indetermined;
GameMission_t gamemission = doom;
GameVersion_t gameversion = exe_final2;
char *gamedescription;
// Set if homebrew PWAD stuff has been added.
boolean modifiedgame;

281
apps/doom/doomstat.h Normal file
View File

@ -0,0 +1,281 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// All the global variables that store the internal state.
// Theoretically speaking, the internal state of the engine
// should be found by looking at the variables collected
// here, and every relevant module will have to include
// this header file.
// In practice, things are a bit messy.
//
#ifndef __D_STATE__
#define __D_STATE__
// We need globally shared data structures,
// for defining the global state variables.
#include "doomdata.h"
#include "d_loop.h"
// We need the playr data structure as well.
#include "d_player.h"
// Game mode/mission
#include "d_mode.h"
#include "net_defs.h"
// ------------------------
// Command line parameters.
//
extern boolean nomonsters; // checkparm of -nomonsters
extern boolean respawnparm; // checkparm of -respawn
extern boolean fastparm; // checkparm of -fast
extern boolean devparm; // DEBUG: launched with -devparm
// -----------------------------------------------------
// Game Mode - identify IWAD as shareware, retail etc.
//
extern GameMode_t gamemode;
extern GameMission_t gamemission;
extern GameVersion_t gameversion;
extern char *gamedescription;
// If true, we're using one of the mangled BFG edition IWADs.
extern boolean bfgedition;
// Convenience macro.
// 'gamemission' can be equal to pack_chex or pack_hacx, but these are
// just modified versions of doom and doom2, and should be interpreted
// as the same most of the time.
#define logical_gamemission \
(gamemission == pack_chex ? doom : \
gamemission == pack_hacx ? doom2 : gamemission)
// Set if homebrew PWAD stuff has been added.
extern boolean modifiedgame;
// -------------------------------------------
// Selected skill type, map etc.
//
// Defaults for menu, methinks.
extern skill_t startskill;
extern int startepisode;
extern int startmap;
// Savegame slot to load on startup. This is the value provided to
// the -loadgame option. If this has not been provided, this is -1.
extern int startloadgame;
extern boolean autostart;
// Selected by user.
extern skill_t gameskill;
extern int gameepisode;
extern int gamemap;
// If non-zero, exit the level after this number of minutes
extern int timelimit;
// Nightmare mode flag, single player.
extern boolean respawnmonsters;
// Netgame? Only true if >1 player.
extern boolean netgame;
// 0=Cooperative; 1=Deathmatch; 2=Altdeath
extern int deathmatch;
// -------------------------
// Internal parameters for sound rendering.
// These have been taken from the DOS version,
// but are not (yet) supported with Linux
// (e.g. no sound volume adjustment with menu.
// From m_menu.c:
// Sound FX volume has default, 0 - 15
// Music volume has default, 0 - 15
// These are multiplied by 8.
extern int sfxVolume;
extern int musicVolume;
// Current music/sfx card - index useless
// w/o a reference LUT in a sound module.
// Ideally, this would use indices found
// in: /usr/include/linux/soundcard.h
extern int snd_MusicDevice;
extern int snd_SfxDevice;
// Config file? Same disclaimer as above.
extern int snd_DesiredMusicDevice;
extern int snd_DesiredSfxDevice;
// -------------------------
// Status flags for refresh.
//
// Depending on view size - no status bar?
// Note that there is no way to disable the
// status bar explicitely.
extern boolean statusbaractive;
extern boolean automapactive; // In AutoMap mode?
extern boolean menuactive; // Menu overlayed?
extern boolean paused; // Game Pause?
extern boolean viewactive;
extern boolean nodrawers;
extern boolean testcontrols;
extern int testcontrols_mousespeed;
// This one is related to the 3-screen display mode.
// ANG90 = left side, ANG270 = right
extern int viewangleoffset;
// Player taking events, and displaying.
extern int consoleplayer;
extern int displayplayer;
// -------------------------------------
// Scores, rating.
// Statistics on a given map, for intermission.
//
extern int totalkills;
extern int totalitems;
extern int totalsecret;
// Timer, for scores.
extern int levelstarttic; // gametic at level start
extern int leveltime; // tics in game play for par
// --------------------------------------
// DEMO playback/recording related stuff.
// No demo, there is a human player in charge?
// Disable save/end game?
extern boolean usergame;
//?
extern boolean demoplayback;
extern boolean demorecording;
// Round angleturn in ticcmds to the nearest 256. This is used when
// recording Vanilla demos in netgames.
extern boolean lowres_turn;
// Quit after playing a demo from cmdline.
extern boolean singledemo;
//?
extern gamestate_t gamestate;
//-----------------------------
// Internal parameters, fixed.
// These are set by the engine, and not changed
// according to user inputs. Partly load from
// WAD, partly set at startup time.
// Bookkeeping on players - state.
extern player_t players[MAXPLAYERS];
// Alive? Disconnected?
extern boolean playeringame[MAXPLAYERS];
// Player spawn spots for deathmatch.
#define MAX_DM_STARTS 10
extern mapthing_t deathmatchstarts[MAX_DM_STARTS];
extern mapthing_t* deathmatch_p;
// Player spawn spots.
extern mapthing_t playerstarts[MAXPLAYERS];
// Intermission stats.
// Parameters for world map / intermission.
extern wbstartstruct_t wminfo;
//-----------------------------------------
// Internal parameters, used for engine.
//
// File handling stuff.
extern char * savegamedir;
extern char basedefault[1024];
// if true, load all graphics at level load
extern boolean precache;
// wipegamestate can be set to -1
// to force a wipe on the next draw
extern gamestate_t wipegamestate;
extern int mouseSensitivity;
extern int bodyqueslot;
// Needed to store the number of the dummy sky flat.
// Used for rendering,
// as well as tracking projectiles etc.
extern int skyflatnum;
// Netgame stuff (buffers and pointers, i.e. indices).
extern int rndindex;
extern ticcmd_t *netcmds;
#endif

54
apps/doom/doomtype.h Normal file
View File

@ -0,0 +1,54 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Simple basic typedefs, isolated here to make it easier
// separating modules.
//
#ifndef __DOOMTYPE__
#define __DOOMTYPE__
// #define macros to provide functions missing in Windows.
// Outside Windows, we use strings.h for str[n]casecmp.
#include "essence/include.h"
//
// The packed attribute forces structures to be packed into the minimum
// space necessary. If this is not done, the compiler may align structure
// fields differently to optimize memory access, inflating the overall
// structure size. It is important to use the packed attribute on certain
// structures where alignment is important, particularly data read/written
// to disk.
//
#ifdef __GNUC__
#define PACKEDATTR __attribute__((packed))
#else
#define PACKEDATTR
#endif
typedef bool boolean;
typedef uint8_t byte;
#define DIR_SEPARATOR '/'
#define DIR_SEPARATOR_S "/"
#define PATH_SEPARATOR ':'
#define arrlen(array) (sizeof(array) / sizeof(*array))
#endif

44
apps/doom/dstrings.c Normal file
View File

@ -0,0 +1,44 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Globally defined strings.
//
#include "dstrings.h"
char *doom1_endmsg[] =
{
"are you sure you want to\nquit this great game?",
"please don't leave, there's more\ndemons to toast!",
"let's beat it -- this is turning\ninto a bloodbath!",
"i wouldn't leave if i were you.\ndos is much worse.",
"you're trying to say you like dos\nbetter than me, right?",
"don't leave yet -- there's a\ndemon around that corner!",
"ya know, next time you come in here\ni'm gonna toast ya.",
"go ahead and leave. see if i care.",
};
char *doom2_endmsg[] =
{
// QuitDOOM II messages
"are you sure you want to\nquit this great game?",
"you want to quit?\nthen, thou hast lost an eighth!",
"don't go now, there's a \ndimensional shambler waiting\nat the dos prompt!",
"get outta here and go back\nto your boring programs.",
"if i were your boss, i'd \n deathmatch ya in a minute!",
"look, bud. you leave now\nand you forfeit your body count!",
"just leave. when you come\nback, i'll be waiting with a bat.",
"you're lucky i don't smack\nyou for thinking about leaving.",
};

36
apps/doom/dstrings.h Normal file
View File

@ -0,0 +1,36 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// DESCRIPTION:
// DOOM strings, by language.
//
#ifndef __DSTRINGS__
#define __DSTRINGS__
// All important printed strings.
#include "d_englsh.h"
// Misc. other strings.
#define SAVEGAMENAME "doomsav"
// QuitDOOM messages
// 8 per each game type
#define NUM_QUITMESSAGES 8
extern char *doom1_endmsg[];
extern char *doom2_endmsg[];
#endif

200
apps/doom/essence/game.c Normal file
View File

@ -0,0 +1,200 @@
#include "include.h"
#include "../config.h"
#include "../doomkeys.h"
#include "../d_main.h"
#include "../m_argv.h"
EsInstance *instance = 0;
pixel_t *ES_ScreenBuffer = 0;
typedef struct {
uint8_t value;
bool pressed;
} KeyEntry;
#define KEY_QUEUE_SIZE 64
static KeyEntry KeyQueue[KEY_QUEUE_SIZE] = { 0 };
static size_t KeyQueueHead = 0;
static size_t KeyQueueTail = 0;
uint8_t ES_TranslateKey(EsScancode scancode) {
switch (scancode) {
case ES_SCANCODE_ENTER: return KEY_ENTER;
case ES_SCANCODE_ESCAPE: return KEY_ESCAPE;
case ES_SCANCODE_LEFT_ARROW: return KEY_LEFTARROW;
case ES_SCANCODE_RIGHT_ARROW: return KEY_RIGHTARROW;
case ES_SCANCODE_UP_ARROW: return KEY_UPARROW;
case ES_SCANCODE_DOWN_ARROW: return KEY_DOWNARROW;
case ES_SCANCODE_LEFT_CTRL:
case ES_SCANCODE_RIGHT_CTRL:
return KEY_FIRE;
case ES_SCANCODE_SPACE: return KEY_USE;
case ES_SCANCODE_LEFT_SHIFT:
case ES_SCANCODE_RIGHT_SHIFT:
return KEY_RSHIFT;
case ES_SCANCODE_LEFT_ALT:
case ES_SCANCODE_RIGHT_ALT:
return KEY_LALT;
case ES_SCANCODE_TAB:
return KEY_TAB;
case ES_SCANCODE_F2: return KEY_F2;
case ES_SCANCODE_F3: return KEY_F3;
case ES_SCANCODE_F4: return KEY_F4;
case ES_SCANCODE_F5: return KEY_F5;
case ES_SCANCODE_F6: return KEY_F6;
case ES_SCANCODE_F7: return KEY_F7;
case ES_SCANCODE_F8: return KEY_F8;
case ES_SCANCODE_F9: return KEY_F9;
case ES_SCANCODE_F10: return KEY_F10;
case ES_SCANCODE_F11: return KEY_F11;
case ES_SCANCODE_EQUALS: return KEY_EQUALS;
case ES_SCANCODE_LEFT_BRACE:
case ES_SCANCODE_RIGHT_BRACE:
return KEY_MINUS;
case ES_SCANCODE_0: return '0';
case ES_SCANCODE_1: return '1';
case ES_SCANCODE_2: return '2';
case ES_SCANCODE_3: return '3';
case ES_SCANCODE_4: return '4';
case ES_SCANCODE_5: return '5';
case ES_SCANCODE_6: return '6';
case ES_SCANCODE_7: return '7';
case ES_SCANCODE_8: return '8';
case ES_SCANCODE_9: return '9';
default:
}
if (ES_SCANCODE_A <= scancode && scancode <= ES_SCANCODE_Z) {
return scancode + ('a' - ES_SCANCODE_A);
}
return 0;
}
uint8_t ES_GetKey(int *pressed, unsigned char *key) {
if (KeyQueueHead == KeyQueueTail) return 0;
KeyEntry entry = KeyQueue[KeyQueueHead];
KeyQueueHead = (KeyQueueHead + 1) % KEY_QUEUE_SIZE;
*key = entry.value;
*pressed = entry.pressed;
return 1;
}
uint32_t ES_GetTicksMs(void) {
return EsTimeStampMs();
}
void ES_SleepMs(uint32_t ms) {
EsSleep(ms);
}
int GameMessage(EsElement *element, EsMessage *message) {
switch (message->type) {
case ES_MSG_ANIMATE: {
D_DoomTick();
EsElementRepaint(element, ES_NULL);
message->animate.complete = false;
return ES_HANDLED;
}
case ES_MSG_PAINT: {
EsPainter *painter = message->painter;
EsDrawRectangle(painter, ES_RECT_4(0, RES_X, 0, RES_Y), 0x000000FF, 0, ES_RECT_1(0));
EsDrawBitmap(painter, ES_RECT_4(0, RES_X, 0, RES_Y), ES_ScreenBuffer, RES_X * 4, ES_DRAW_BITMAP_OPAQUE);
return ES_HANDLED;
}
case ES_MSG_GET_WIDTH: {
message->measure.width = RES_X;
return ES_HANDLED;
}
case ES_MSG_GET_HEIGHT: {
message->measure.height = RES_Y;
return ES_HANDLED;
}
case ES_MSG_KEY_UP:
case ES_MSG_KEY_DOWN: {
uint8_t key = ES_TranslateKey(message->keyboard.scancode);
if (key == 0) return ES_HANDLED;
KeyQueue[KeyQueueTail] = (KeyEntry) {
.value = key,
.pressed = message->type == ES_MSG_KEY_DOWN
};
KeyQueueTail = (KeyQueueTail + 1) % KEY_QUEUE_SIZE;
return ES_HANDLED;
}
default:
return 0;
}
}
int ApplicationMessage(EsMessage *message) {
switch (message->type) {
case ES_MSG_INSTANCE_CREATE: {
instance = EsInstanceCreate(message, "DOOM", -1);
EsWindowSetIcon(instance->window, ES_ICON_APPLICATIONS_GAMES);
EsPanel *panel = EsPanelCreate(instance->window, ES_CELL_FILL, 0);
EsSpacerCreate(panel, ES_CELL_CENTER, 0, 0, 0);
EsElement *game = EsCustomElementCreate(panel, ES_ELEMENT_FOCUSABLE, 0);
game->messageUser = GameMessage;
ES_Init();
EsElementFocus(game, ES_FLAGS_DEFAULT);
EsElementStartAnimating(game);
return ES_HANDLED;
}
default:
return ES_HANDLED;
}
}
static char *ES_ARGV[] = { "doom" };
static int ES_ARGC = sizeof(ES_ARGV) / sizeof(char *);
void ES_Init(void) {
myargc = ES_ARGC;
myargv = ES_ARGV;
ES_ScreenBuffer = ES_malloc(RES_X * RES_Y * 4);
D_DoomMain();
}
void ES_Loop(void) {
while (true) ApplicationMessage(EsMessageReceive());
}
void ES_Crash(const char *message) {
ES_crashf("%s\n", message);
EsPanic("");
}
void ES_Exit() {
if (instance) EsInstanceClose(instance);
EsProcessTerminate(ES_CURRENT_PROCESS, 0);
}

159
apps/doom/essence/include.h Normal file
View File

@ -0,0 +1,159 @@
#ifndef __ES_INCLUDE__
#define __ES_INCLUDE__
#include <essence.h>
#include "../config.h"
/* Logging */
void ES_logf(const char *label, const char *format, ...);
#ifdef FEATURE_CONSOLE
#define ES_infof(format, ...) ES_logf("[Info:DOOM] ", format, ## __VA_ARGS__)
#define ES_debugf(format, ...) ES_logf("[Debug:DOOM] ", format, ## __VA_ARGS__)
#define ES_warnf(format, ...) ES_logf("[Warn:DOOM] ", format, ## __VA_ARGS__)
#define ES_errorf(format, ...) ES_logf("[Error:DOOM] ", format, ## __VA_ARGS__)
#define ES_crashf(format, ...) ES_logf("[Crash:DOOM] ", format, ## __VA_ARGS__)
#else
#define ES_infof(format, ...)
#define ES_debugf(format, ...)
#define ES_warnf(format, ...)
#define ES_errorf(format, ...)
#define ES_crashf(format, ...)
#endif
/* Process */
__attribute__((noreturn))
void ES_Crash(const char *message);
__attribute__((noreturn))
void ES_Exit();
/* Math */
int ES_atoi(const char *str);
#define ES_atoi EsCRTatoi
float ES_atof(const char *str);
#define ES_atof EsCRTatof
int ES_abs(int n);
#define ES_abs EsCRTabs
float ES_fabs(float n);
#define ES_fabs EsCRTfabs
/* String */
int ES_strcasecmp(const char *s1, const char *s2);
int ES_strncasecmp(const char *s1, const char *s2, size_t count);
char ES_toupper(char c);
char ES_tolower(char c);
#define ES_tolower EsCRTtolower
void *ES_memcpy(void *destination, const void *source, size_t num);
#define ES_memcpy EsCRTmemcpy
void *ES_memset(void *ptr, int value, size_t num);
#define ES_memset EsCRTmemset
const char *ES_strchr(const char *str, int character);
#define ES_strchr EsCRTstrchr
size_t ES_strlen(const char *str);
#define ES_strlen EsCRTstrlen
int ES_strcmp(const char *s1, const char *s2);
#define ES_strcmp EsCRTstrcmp
int ES_strncmp(const char *s1, const char *s2, size_t count);
#define ES_strncmp EsCRTstrncmp
int ES_strstr(const char *haystack, const char *needle);
#define ES_strstr EsCRTstrstr
int ES_strcpy(char *dest, const char *src);
#define ES_strcpy EsCRTstrcpy
int ES_strncpy(char *dest, const char *src, size_t n);
#define ES_strncpy EsCRTstrncpy
int ES_isspace(int c);
#define ES_isspace EsCRTisspace
int ES_vsnprintf(char *buffer, size_t size, const char *format, va_list arguments);
#define ES_vsnprintf EsCRTvsnprintf
char *ES_strdup(const char *str);
#define ES_strdup EsCRTstrdup
long ES_strtol(const char *ptr, char **endptr, int base);
#define ES_strtol EsCRTstrtol
/* File */
typedef struct {
EsFileInformation data;
size_t ptr;
} ES_File;
typedef enum {
ES_BYTE_MODE = 0b1,
ES_READ_MODE = 0b10,
ES_WRITE_MODE = 0b100
} ES_FileMode;
typedef enum {
ES_SEEK_END,
ES_SEEK_SET
} ES_Seek;
ES_File *ES_fopen(const char *path, ES_FileMode mode);
int ES_fvalid(ES_File *file);
size_t ES_fread(void *buffer, size_t size, size_t count, ES_File *file);
size_t ES_fwrite(const void *buffer, size_t size, size_t count, ES_File *file);
int ES_fseek(ES_File *file, size_t offset, ES_Seek origin);
size_t ES_ftell(ES_File *file);
size_t ES_fprintf(ES_File *file, const char *format, ...);
void ES_fclose(ES_File *file);
int ES_mkdir(const char *path);
int ES_remove(const char *path);
int ES_rename(const char *old, const char *new);
/* Heap */
void *ES_malloc(size_t size);
#define ES_malloc EsCRTmalloc
void *ES_calloc(size_t num, size_t size);
#define ES_calloc EsCRTcalloc
void *ES_realloc(void *ptr, size_t size);
#define ES_realloc EsCRTrealloc
void ES_free(void *ptr);
#define ES_free EsCRTfree
/* Graphics */
#ifdef CMAP256
typedef uint8_t pixel_t;
#else
typedef uint32_t pixel_t;
#endif
extern pixel_t* ES_ScreenBuffer;
/* Game */
void ES_Loop(void);
void ES_SleepMs(uint32_t ms);
uint32_t ES_GetTicksMs(void);
uint8_t ES_GetKey(int *pressed, unsigned char *key);
#endif

200
apps/doom/essence/lib.c Normal file
View File

@ -0,0 +1,200 @@
#include "include.h"
static char ES_LOG_BUFFER[4096];
void ES_vlogf(const char *label, const char *format, va_list args) {
size_t label_size = ES_strlen(label);
ES_memcpy(ES_LOG_BUFFER, label, label_size);
size_t data_size = ES_vsnprintf(ES_LOG_BUFFER + label_size, sizeof(ES_LOG_BUFFER), format, args);
ES_LOG_BUFFER[sizeof(ES_LOG_BUFFER) - 1] = '\0';
EsPrintDirect(ES_LOG_BUFFER, data_size + label_size);
}
void ES_logf(const char *label, const char *format, ...) {
va_list args;
va_start(args, format);
ES_vlogf(label, format, args);
va_end(args);
}
char ES_toupper(char c) {
return (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c;
}
int ES_strcasecmp(const char *s1, const char *s2) {
int c1, c2;
for (;;) {
c1 = ES_tolower(*s1++);
c2 = ES_tolower(*s2++);
if (c1 != c2) {
return c1 - c2;
}
if (c1 == '\0') break;
}
return 0;
}
int ES_strncasecmp(const char *s1, const char *s2, register size_t n) {
int c1, c2;
for (; n != 0; --n) {
c1 = ES_tolower(*s1++);
c2 = ES_tolower(*s2++);
if (c1 != c2) {
return c1 - c2;
}
if (c1 == '\0') break;
}
return 0;
}
ES_File *ES_fopen(const char *path, ES_FileMode mode) {
EsFileOpenFlags flags;
if (mode & ES_WRITE_MODE) flags = ES_FILE_WRITE;
else flags = ES_FILE_READ;
if (flags & ES_FILE_READ) {
EsNodeType nodeType;
if (!EsPathExists(path, ES_strlen(path), &nodeType) || nodeType != ES_NODE_FILE) {
return NULL;
}
}
EsFileInformation data = EsFileOpen(path, ES_strlen(path), flags);
if (data.error != ES_SUCCESS) {
EsHandleClose(data.handle);
return NULL;
}
ES_File *file = ES_malloc(sizeof(ES_File));
if (file == NULL) {
EsHandleClose(data.handle);
return NULL;
}
file->ptr = 0;
file->data = data;
return file;
}
int ES_fvalid(ES_File *file) {
return file->data.error == ES_SUCCESS;
}
size_t ES_fread(void *buffer, size_t size, size_t count, ES_File *file) {
size_t offset = EsFileReadSync(file->data.handle, file->ptr, size * count, buffer);
file->ptr += offset;
return offset;
}
size_t ES_fwrite(const void *buffer, size_t size, size_t count, ES_File *file) {
size_t offset = EsFileWriteSync(file->data.handle, file->ptr, size * count, buffer);
file->ptr += offset;
return offset;
}
int ES_fseek(ES_File *file, size_t offset, ES_Seek origin) {
switch (origin) {
case ES_SEEK_SET:
if (offset >= file->data.size) return -1;
file->ptr = offset;
return 0;
case ES_SEEK_END:
file->ptr = file->data.size + 1;
return 0;
default: return -1;
}
}
size_t ES_ftell(ES_File *file) {
return file->ptr;
}
size_t ES_fprintf(ES_File *file, const char *format, ...) {
size_t max_size = ES_strlen(format) * 4;
void *buffer = ES_malloc(max_size);
va_list args;
va_start(args, format);
ES_vsnprintf(buffer, max_size, format, args);
va_end(args);
size_t size = ES_strlen(buffer);
size_t write_size = ES_fwrite(buffer, size, 1, file);
ES_free(buffer);
return write_size;
}
void ES_fclose(ES_File *file) {
EsHandleClose(file->data.handle);
ES_free(file);
}
int ES_remove(const char *path) {
EsFileInformation file = EsFileOpen(path, ES_strlen(path), ES_FILE_WRITE);
if (file.error != ES_SUCCESS) {
EsHandleClose(file.handle);
return -1;
}
EsFileDelete(file.handle);
EsHandleClose(file.handle);
return 0;
}
int ES_rename(const char *old, const char *new) {
EsFileInformation oldFile = EsFileOpen(old, ES_strlen(old), ES_FILE_READ | ES_FILE_WRITE);
if (oldFile.error != ES_SUCCESS) {
EsHandleClose(oldFile.handle);
return -1;
}
if (EsPathCreate(new, ES_strlen(new), ES_NODE_FILE, true) != ES_SUCCESS) {
EsHandleClose(oldFile.handle);
return -1;
}
EsFileInformation newFile = EsFileOpen(new, ES_strlen(new), ES_FILE_WRITE);
if (newFile.error != ES_SUCCESS) {
EsHandleClose(oldFile.handle);
EsHandleClose(newFile.handle);
return -1;
}
void *buffer = ES_malloc(oldFile.size);
EsFileReadSync(oldFile.handle, 0, oldFile.size, buffer);
EsFileWriteSync(newFile.handle, 0, newFile.size, buffer);
ES_free(buffer);
EsFileDelete(oldFile.handle);
EsHandleClose(oldFile.handle);
EsHandleClose(newFile.handle);
return 0;
}
int ES_mkdir(const char *path) {
return EsPathCreate(path, ES_strlen(path), ES_NODE_DIRECTORY, true) == ES_SUCCESS;
}

91
apps/doom/essence/main.c Normal file
View File

@ -0,0 +1,91 @@
#include "include.h"
#include "../am_map.c"
#include "../d_event.c"
#include "../d_items.c"
#include "../d_iwad.c"
#include "../d_loop.c"
#include "../d_main.c"
#include "../d_mode.c"
#include "../d_net.c"
#include "../doomstat.c"
#include "../dstrings.c"
#include "../f_finale.c"
#include "../f_wipe.c"
#include "../g_game.c"
#include "../gusconf.c"
#include "../hu_lib.c"
#include "../hu_stuff.c"
#include "../i_input.c"
#include "../i_joystick.c"
#include "../info.c"
#include "../i_scale.c"
#include "../i_sound.c"
#include "../i_system.c"
#include "../i_timer.c"
#include "../i_video.c"
#include "../m_argv.c"
#include "../m_bbox.c"
#include "../m_cheat.c"
#include "../m_config.c"
#include "../m_controls.c"
#include "../memio.c"
#include "../m_fixed.c"
#include "../m_menu.c"
#include "../m_misc.c"
#include "../m_random.c"
#include "../mus2mid.c"
#include "../net_client.c"
#include "../p_ceilng.c"
#include "../p_doors.c"
#include "../p_enemy.c"
#include "../p_floor.c"
#include "../p_inter.c"
#include "../p_lights.c"
#include "../p_map.c"
#include "../p_maputl.c"
#include "../p_mobj.c"
#include "../p_plats.c"
#include "../p_pspr.c"
#include "../p_saveg.c"
#include "../p_setup.c"
#include "../p_sight.c"
#include "../p_spec.c"
#include "../p_switch.c"
#include "../p_telept.c"
#include "../p_tick.c"
#include "../p_user.c"
#include "../r_bsp.c"
#include "../r_data.c"
#include "../r_draw.c"
#include "../r_main.c"
#include "../r_plane.c"
#include "../r_segs.c"
#include "../r_sky.c"
#include "../r_things.c"
#include "../sha1.c"
#include "../sounds.c"
#include "../s_sound.c"
#include "../statdump.c"
#include "../st_lib.c"
#include "../st_stuff.c"
#include "../tables.c"
#include "../v_video.c"
#include "../w_checksum.c"
#include "../w_file.c"
#include "../w_file_stdc.c"
#include "../wi_stuff.c"
#include "../w_main.c"
#include "../w_wad.c"
#include "../z_zone.c"
#include "lib.c"
#include "game.c"
void _start() {
_init();
ES_debugf("Started\n");
ES_Loop();
}

705
apps/doom/f_finale.c Normal file
View File

@ -0,0 +1,705 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Game completion, final screen animation.
//
#include "essence/include.h"
// Functions.
#include "i_system.h"
#include "i_swap.h"
#include "z_zone.h"
#include "v_video.h"
#include "w_wad.h"
#include "s_sound.h"
// Data.
#include "d_main.h"
#include "dstrings.h"
#include "sounds.h"
#include "doomstat.h"
#include "r_state.h"
typedef enum
{
F_STAGE_TEXT,
F_STAGE_ARTSCREEN,
F_STAGE_CAST,
} finalestage_t;
// ?
//#include "doomstat.h"
//#include "r_local.h"
//#include "f_finale.h"
// Stage of animation:
finalestage_t finalestage;
unsigned int finalecount;
#define TEXTSPEED 3
#define TEXTWAIT 250
typedef struct
{
GameMission_t mission;
int episode, level;
char *background;
char *text;
} textscreen_t;
static textscreen_t textscreens[] =
{
{ doom, 1, 8, "FLOOR4_8", E1TEXT},
{ doom, 2, 8, "SFLR6_1", E2TEXT},
{ doom, 3, 8, "MFLR8_4", E3TEXT},
{ doom, 4, 8, "MFLR8_3", E4TEXT},
{ doom2, 1, 6, "SLIME16", C1TEXT},
{ doom2, 1, 11, "RROCK14", C2TEXT},
{ doom2, 1, 20, "RROCK07", C3TEXT},
{ doom2, 1, 30, "RROCK17", C4TEXT},
{ doom2, 1, 15, "RROCK13", C5TEXT},
{ doom2, 1, 31, "RROCK19", C6TEXT},
{ pack_tnt, 1, 6, "SLIME16", T1TEXT},
{ pack_tnt, 1, 11, "RROCK14", T2TEXT},
{ pack_tnt, 1, 20, "RROCK07", T3TEXT},
{ pack_tnt, 1, 30, "RROCK17", T4TEXT},
{ pack_tnt, 1, 15, "RROCK13", T5TEXT},
{ pack_tnt, 1, 31, "RROCK19", T6TEXT},
{ pack_plut, 1, 6, "SLIME16", P1TEXT},
{ pack_plut, 1, 11, "RROCK14", P2TEXT},
{ pack_plut, 1, 20, "RROCK07", P3TEXT},
{ pack_plut, 1, 30, "RROCK17", P4TEXT},
{ pack_plut, 1, 15, "RROCK13", P5TEXT},
{ pack_plut, 1, 31, "RROCK19", P6TEXT},
};
char* finaletext;
char* finaleflat;
void F_StartCast (void);
void F_CastTicker (void);
boolean F_CastResponder (event_t *ev);
void F_CastDrawer (void);
//
// F_StartFinale
//
void F_StartFinale (void)
{
size_t i;
gameaction = ga_nothing;
gamestate = GS_FINALE;
viewactive = false;
automapactive = false;
if (logical_gamemission == doom)
{
S_ChangeMusic(mus_victor, true);
}
else
{
S_ChangeMusic(mus_read_m, true);
}
// Find the right screen and set the text and background
for (i=0; i<arrlen(textscreens); ++i)
{
textscreen_t *screen = &textscreens[i];
// Hack for Chex Quest
if (gameversion == exe_chex && screen->mission == doom)
{
screen->level = 5;
}
if (logical_gamemission == screen->mission
&& (logical_gamemission != doom || gameepisode == screen->episode)
&& gamemap == screen->level)
{
finaletext = screen->text;
finaleflat = screen->background;
}
}
finalestage = F_STAGE_TEXT;
finalecount = 0;
}
boolean F_Responder (event_t *event)
{
if (finalestage == F_STAGE_CAST)
return F_CastResponder (event);
return false;
}
//
// F_Ticker
//
void F_Ticker (void)
{
size_t i;
// check for skipping
if ( (gamemode == commercial)
&& ( finalecount > 50) )
{
// go on to the next level
for (i=0 ; i<MAXPLAYERS ; i++)
if (players[i].cmd.buttons)
break;
if (i < MAXPLAYERS)
{
if (gamemap == 30)
F_StartCast ();
else
gameaction = ga_worlddone;
}
}
// advance animation
finalecount++;
if (finalestage == F_STAGE_CAST)
{
F_CastTicker ();
return;
}
if ( gamemode == commercial)
return;
if (finalestage == F_STAGE_TEXT
&& finalecount>ES_strlen (finaletext)*TEXTSPEED + TEXTWAIT)
{
finalecount = 0;
finalestage = F_STAGE_ARTSCREEN;
wipegamestate = -1; // force a wipe
if (gameepisode == 3)
S_StartMusic (mus_bunny);
}
}
//
// F_TextWrite
//
#include "hu_stuff.h"
extern patch_t *hu_font[HU_FONTSIZE];
void F_TextWrite (void)
{
byte* src;
byte* dest;
int x,y,w;
signed int count;
char* ch;
int c;
int cx;
int cy;
// erase the entire screen to a tiled background
src = W_CacheLumpName ( finaleflat , PU_CACHE);
dest = I_VideoBuffer;
for (y=0 ; y<SCREENHEIGHT ; y++)
{
for (x=0 ; x<SCREENWIDTH/64 ; x++)
{
ES_memcpy (dest, src+((y&63)<<6), 64);
dest += 64;
}
if (SCREENWIDTH&63)
{
ES_memcpy (dest, src+((y&63)<<6), SCREENWIDTH&63);
dest += (SCREENWIDTH&63);
}
}
V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
// draw some of the text onto the screen
cx = 10;
cy = 10;
ch = finaletext;
count = ((signed int) finalecount - 10) / TEXTSPEED;
if (count < 0)
count = 0;
for ( ; count ; count-- )
{
c = *ch++;
if (!c)
break;
if (c == '\n')
{
cx = 10;
cy += 11;
continue;
}
c = ES_toupper(c) - HU_FONTSTART;
if (c < 0 || c> HU_FONTSIZE)
{
cx += 4;
continue;
}
w = SHORT (hu_font[c]->width);
if (cx+w > SCREENWIDTH)
break;
V_DrawPatch(cx, cy, hu_font[c]);
cx+=w;
}
}
//
// Final DOOM 2 animation
// Casting by id Software.
// in order of appearance
//
typedef struct
{
char *name;
mobjtype_t type;
} castinfo_t;
castinfo_t castorder[] = {
{CC_ZOMBIE, MT_POSSESSED},
{CC_SHOTGUN, MT_SHOTGUY},
{CC_HEAVY, MT_CHAINGUY},
{CC_IMP, MT_TROOP},
{CC_DEMON, MT_SERGEANT},
{CC_LOST, MT_SKULL},
{CC_CACO, MT_HEAD},
{CC_HELL, MT_KNIGHT},
{CC_BARON, MT_BRUISER},
{CC_ARACH, MT_BABY},
{CC_PAIN, MT_PAIN},
{CC_REVEN, MT_UNDEAD},
{CC_MANCU, MT_FATSO},
{CC_ARCH, MT_VILE},
{CC_SPIDER, MT_SPIDER},
{CC_CYBER, MT_CYBORG},
{CC_HERO, MT_PLAYER},
{NULL,0}
};
int castnum;
int casttics;
state_t* caststate;
boolean castdeath;
int castframes;
int castonmelee;
boolean castattacking;
//
// F_StartCast
//
void F_StartCast (void)
{
wipegamestate = -1; // force a screen wipe
castnum = 0;
caststate = &states[mobjinfo[castorder[castnum].type].seestate];
casttics = caststate->tics;
castdeath = false;
finalestage = F_STAGE_CAST;
castframes = 0;
castonmelee = 0;
castattacking = false;
S_ChangeMusic(mus_evil, true);
}
//
// F_CastTicker
//
void F_CastTicker (void)
{
int st;
int sfx;
if (--casttics > 0)
return; // not time to change state yet
if (caststate->tics == -1 || caststate->nextstate == S_NULL)
{
// switch from deathstate to next monster
castnum++;
castdeath = false;
if (castorder[castnum].name == NULL)
castnum = 0;
if (mobjinfo[castorder[castnum].type].seesound)
S_StartSound (NULL, mobjinfo[castorder[castnum].type].seesound);
caststate = &states[mobjinfo[castorder[castnum].type].seestate];
castframes = 0;
}
else
{
// just advance to next state in animation
if (caststate == &states[S_PLAY_ATK1])
goto stopattack; // Oh, gross hack!
st = caststate->nextstate;
caststate = &states[st];
castframes++;
// sound hacks....
switch (st)
{
case S_PLAY_ATK1: sfx = sfx_dshtgn; break;
case S_POSS_ATK2: sfx = sfx_pistol; break;
case S_SPOS_ATK2: sfx = sfx_shotgn; break;
case S_VILE_ATK2: sfx = sfx_vilatk; break;
case S_SKEL_FIST2: sfx = sfx_skeswg; break;
case S_SKEL_FIST4: sfx = sfx_skepch; break;
case S_SKEL_MISS2: sfx = sfx_skeatk; break;
case S_FATT_ATK8:
case S_FATT_ATK5:
case S_FATT_ATK2: sfx = sfx_firsht; break;
case S_CPOS_ATK2:
case S_CPOS_ATK3:
case S_CPOS_ATK4: sfx = sfx_shotgn; break;
case S_TROO_ATK3: sfx = sfx_claw; break;
case S_SARG_ATK2: sfx = sfx_sgtatk; break;
case S_BOSS_ATK2:
case S_BOS2_ATK2:
case S_HEAD_ATK2: sfx = sfx_firsht; break;
case S_SKULL_ATK2: sfx = sfx_sklatk; break;
case S_SPID_ATK2:
case S_SPID_ATK3: sfx = sfx_shotgn; break;
case S_BSPI_ATK2: sfx = sfx_plasma; break;
case S_CYBER_ATK2:
case S_CYBER_ATK4:
case S_CYBER_ATK6: sfx = sfx_rlaunc; break;
case S_PAIN_ATK3: sfx = sfx_sklatk; break;
default: sfx = 0; break;
}
if (sfx)
S_StartSound (NULL, sfx);
}
if (castframes == 12)
{
// go into attack frame
castattacking = true;
if (castonmelee)
caststate=&states[mobjinfo[castorder[castnum].type].meleestate];
else
caststate=&states[mobjinfo[castorder[castnum].type].missilestate];
castonmelee ^= 1;
if (caststate == &states[S_NULL])
{
if (castonmelee)
caststate=
&states[mobjinfo[castorder[castnum].type].meleestate];
else
caststate=
&states[mobjinfo[castorder[castnum].type].missilestate];
}
}
if (castattacking)
{
if (castframes == 24
|| caststate == &states[mobjinfo[castorder[castnum].type].seestate] )
{
stopattack:
castattacking = false;
castframes = 0;
caststate = &states[mobjinfo[castorder[castnum].type].seestate];
}
}
casttics = caststate->tics;
if (casttics == -1)
casttics = 15;
}
//
// F_CastResponder
//
boolean F_CastResponder (event_t* ev)
{
if (ev->type != ev_keydown)
return false;
if (castdeath)
return true; // already in dying frames
// go into death frame
castdeath = true;
caststate = &states[mobjinfo[castorder[castnum].type].deathstate];
casttics = caststate->tics;
castframes = 0;
castattacking = false;
if (mobjinfo[castorder[castnum].type].deathsound)
S_StartSound (NULL, mobjinfo[castorder[castnum].type].deathsound);
return true;
}
void F_CastPrint (char* text)
{
char* ch;
int c;
int cx;
int w;
int width;
// find width
ch = text;
width = 0;
while (ch)
{
c = *ch++;
if (!c)
break;
c = ES_toupper(c) - HU_FONTSTART;
if (c < 0 || c> HU_FONTSIZE)
{
width += 4;
continue;
}
w = SHORT (hu_font[c]->width);
width += w;
}
// draw it
cx = 160-width/2;
ch = text;
while (ch)
{
c = *ch++;
if (!c)
break;
c = ES_toupper(c) - HU_FONTSTART;
if (c < 0 || c> HU_FONTSIZE)
{
cx += 4;
continue;
}
w = SHORT (hu_font[c]->width);
V_DrawPatch(cx, 180, hu_font[c]);
cx+=w;
}
}
//
// F_CastDrawer
//
void F_CastDrawer (void)
{
spritedef_t* sprdef;
spriteframe_t* sprframe;
int lump;
boolean flip;
patch_t* patch;
// erase the entire screen to a background
V_DrawPatch (0, 0, W_CacheLumpName ("BOSSBACK", PU_CACHE));
F_CastPrint (castorder[castnum].name);
// draw the current frame in the middle of the screen
sprdef = &sprites[caststate->sprite];
sprframe = &sprdef->spriteframes[ caststate->frame & FF_FRAMEMASK];
lump = sprframe->lump[0];
flip = (boolean)sprframe->flip[0];
patch = W_CacheLumpNum (lump+firstspritelump, PU_CACHE);
if (flip)
V_DrawPatchFlipped(160, 170, patch);
else
V_DrawPatch(160, 170, patch);
}
//
// F_DrawPatchCol
//
void
F_DrawPatchCol
( int x,
patch_t* patch,
int col )
{
column_t* column;
byte* source;
byte* dest;
byte* desttop;
int count;
column = (column_t *)((byte *)patch + LONG(patch->columnofs[col]));
desttop = I_VideoBuffer + x;
// step through the posts in a column
while (column->topdelta != 0xff )
{
source = (byte *)column + 3;
dest = desttop + column->topdelta*SCREENWIDTH;
count = column->length;
while (count--)
{
*dest = *source++;
dest += SCREENWIDTH;
}
column = (column_t *)( (byte *)column + column->length + 4 );
}
}
//
// F_BunnyScroll
//
void F_BunnyScroll (void)
{
signed int scrolled;
int x;
patch_t* p1;
patch_t* p2;
char name[10];
int stage;
static int laststage;
p1 = W_CacheLumpName ("PFUB2", PU_LEVEL);
p2 = W_CacheLumpName ("PFUB1", PU_LEVEL);
V_MarkRect (0, 0, SCREENWIDTH, SCREENHEIGHT);
scrolled = (320 - ((signed int) finalecount-230)/2);
if (scrolled > 320)
scrolled = 320;
if (scrolled < 0)
scrolled = 0;
for ( x=0 ; x<SCREENWIDTH ; x++)
{
if (x+scrolled < 320)
F_DrawPatchCol (x, p1, x+scrolled);
else
F_DrawPatchCol (x, p2, x+scrolled - 320);
}
if (finalecount < 1130)
return;
if (finalecount < 1180)
{
V_DrawPatch((SCREENWIDTH - 13 * 8) / 2,
(SCREENHEIGHT - 8 * 8) / 2,
W_CacheLumpName("END0", PU_CACHE));
laststage = 0;
return;
}
stage = (finalecount-1180) / 5;
if (stage > 6)
stage = 6;
if (stage > laststage)
{
S_StartSound (NULL, sfx_pistol);
laststage = stage;
}
M_snprintf(name, 10, "END%i", stage);
V_DrawPatch((SCREENWIDTH - 13 * 8) / 2,
(SCREENHEIGHT - 8 * 8) / 2,
W_CacheLumpName (name,PU_CACHE));
}
static void F_ArtScreenDrawer(void)
{
char *lumpname;
if (gameepisode == 3)
{
F_BunnyScroll();
}
else
{
switch (gameepisode)
{
case 1:
if (gamemode == retail)
{
lumpname = "CREDIT";
}
else
{
lumpname = "HELP2";
}
break;
case 2:
lumpname = "VICTORY2";
break;
case 4:
lumpname = "ENDPIC";
break;
default:
return;
}
V_DrawPatch (0, 0, W_CacheLumpName(lumpname, PU_CACHE));
}
}
//
// F_Drawer
//
void F_Drawer (void)
{
switch (finalestage)
{
case F_STAGE_CAST:
F_CastDrawer();
break;
case F_STAGE_TEXT:
F_TextWrite();
break;
case F_STAGE_ARTSCREEN:
F_ArtScreenDrawer();
break;
}
}

40
apps/doom/f_finale.h Normal file
View File

@ -0,0 +1,40 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
//
//
#ifndef __F_FINALE__
#define __F_FINALE__
#include "doomtype.h"
#include "d_event.h"
//
// FINALE
//
// Called by main loop.
boolean F_Responder (event_t* ev);
// Called by main loop.
void F_Ticker (void);
// Called by main loop.
void F_Drawer (void);
void F_StartFinale (void);
#endif

297
apps/doom/f_wipe.c Normal file
View File

@ -0,0 +1,297 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Mission begin melt/wipe screen special effect.
//
#include "essence/include.h"
#include "z_zone.h"
#include "i_video.h"
#include "v_video.h"
#include "m_random.h"
#include "doomtype.h"
#include "f_wipe.h"
//
// SCREEN WIPE PACKAGE
//
// when zero, stop the wipe
static boolean go = 0;
static byte* wipe_scr_start;
static byte* wipe_scr_end;
static byte* wipe_scr;
void
wipe_shittyColMajorXform
( short* array,
int width,
int height )
{
int x;
int y;
short* dest;
dest = (short*) Z_Malloc(width*height*2, PU_STATIC, 0);
for(y=0;y<height;y++)
for(x=0;x<width;x++)
dest[x*height+y] = array[y*width+x];
ES_memcpy(array, dest, width*height*2);
Z_Free(dest);
}
int
wipe_initColorXForm
( int width,
int height,
int ticks )
{
ES_memcpy(wipe_scr, wipe_scr_start, width*height);
return 0;
}
int
wipe_doColorXForm
( int width,
int height,
int ticks )
{
boolean changed;
byte* w;
byte* e;
int newval;
changed = false;
w = wipe_scr;
e = wipe_scr_end;
while (w!=wipe_scr+width*height)
{
if (*w != *e)
{
if (*w > *e)
{
newval = *w - ticks;
if (newval < *e)
*w = *e;
else
*w = newval;
changed = true;
}
else if (*w < *e)
{
newval = *w + ticks;
if (newval > *e)
*w = *e;
else
*w = newval;
changed = true;
}
}
w++;
e++;
}
return !changed;
}
int
wipe_exitColorXForm
( int width,
int height,
int ticks )
{
return 0;
}
static int* y;
int
wipe_initMelt
( int width,
int height,
int ticks )
{
int i, r;
// copy start screen to main screen
ES_memcpy(wipe_scr, wipe_scr_start, width*height);
// makes this wipe faster (in theory)
// to have stuff in column-major format
wipe_shittyColMajorXform((short*)wipe_scr_start, width/2, height);
wipe_shittyColMajorXform((short*)wipe_scr_end, width/2, height);
// setup initial column positions
// (y<0 => not ready to scroll yet)
y = (int *) Z_Malloc(width*sizeof(int), PU_STATIC, 0);
y[0] = -(M_Random()%16);
for (i=1;i<width;i++)
{
r = (M_Random()%3) - 1;
y[i] = y[i-1] + r;
if (y[i] > 0) y[i] = 0;
else if (y[i] == -16) y[i] = -15;
}
return 0;
}
int
wipe_doMelt
( int width,
int height,
int ticks)
{
int i;
int j;
int dy;
int idx;
short* s;
short* d;
boolean done = true;
width/=2;
while (ticks--)
{
for (i=0;i<width;i++)
{
if (y[i]<0)
{
y[i]++; done = false;
}
else if (y[i] < height)
{
dy = (y[i] < 16) ? y[i]+1 : 8;
if (y[i]+dy >= height) dy = height - y[i];
s = &((short *)wipe_scr_end)[i*height+y[i]];
d = &((short *)wipe_scr)[y[i]*width+i];
idx = 0;
for (j=dy;j;j--)
{
d[idx] = *(s++);
idx += width;
}
y[i] += dy;
s = &((short *)wipe_scr_start)[i*height];
d = &((short *)wipe_scr)[y[i]*width+i];
idx = 0;
for (j=height-y[i];j;j--)
{
d[idx] = *(s++);
idx += width;
}
done = false;
}
}
}
return done;
}
int
wipe_exitMelt
( int width,
int height,
int ticks )
{
Z_Free(y);
Z_Free(wipe_scr_start);
Z_Free(wipe_scr_end);
return 0;
}
int
wipe_StartScreen
( int x,
int y,
int width,
int height )
{
wipe_scr_start = Z_Malloc(SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL);
I_ReadScreen(wipe_scr_start);
return 0;
}
int
wipe_EndScreen
( int x,
int y,
int width,
int height )
{
wipe_scr_end = Z_Malloc(SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL);
I_ReadScreen(wipe_scr_end);
V_DrawBlock(x, y, width, height, wipe_scr_start); // restore start scr.
return 0;
}
int
wipe_ScreenWipe
( int wipeno,
int x,
int y,
int width,
int height,
int ticks )
{
int rc;
static int (*wipes[])(int, int, int) =
{
wipe_initColorXForm,
wipe_doColorXForm,
wipe_exitColorXForm,
wipe_initMelt,
wipe_doMelt,
wipe_exitMelt
};
// initial stuff
if (!go)
{
go = 1;
// wipe_scr = (byte *) Z_Malloc(width*height, PU_STATIC, 0); // DEBUG
wipe_scr = I_VideoBuffer;
(*wipes[wipeno*3])(width, height, ticks);
}
// do a piece of wipe-in
V_MarkRect(0, 0, width, height);
rc = (*wipes[wipeno*3+1])(width, height, ticks);
// V_DrawBlock(x, y, 0, width, height, wipe_scr); // DEBUG
// final stuff
if (rc)
{
go = 0;
(*wipes[wipeno*3+2])(width, height, ticks);
}
return !go;
}

62
apps/doom/f_wipe.h Normal file
View File

@ -0,0 +1,62 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Mission start screen wipe/melt, special effects.
//
#ifndef __F_WIPE_H__
#define __F_WIPE_H__
//
// SCREEN WIPE PACKAGE
//
enum
{
// simple gradual pixel change for 8-bit only
wipe_ColorXForm,
// weird screen melt
wipe_Melt,
wipe_NUMWIPES
};
int
wipe_StartScreen
( int x,
int y,
int width,
int height );
int
wipe_EndScreen
( int x,
int y,
int width,
int height );
int
wipe_ScreenWipe
( int wipeno,
int x,
int y,
int width,
int height,
int ticks );
#endif

2252
apps/doom/g_game.c Normal file

File diff suppressed because it is too large Load Diff

79
apps/doom/g_game.h Normal file
View File

@ -0,0 +1,79 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Duh.
//
#ifndef __G_GAME__
#define __G_GAME__
#include "doomdef.h"
#include "d_event.h"
#include "d_ticcmd.h"
//
// GAME
//
void G_DeathMatchSpawnPlayer (int playernum);
void G_InitNew (skill_t skill, int episode, int map);
// Can be called by the startup code or M_Responder.
// A normal game starts at map 1,
// but a warp test can start elsewhere
void G_DeferedInitNew (skill_t skill, int episode, int map);
void G_DeferedPlayDemo (char* demo);
// Can be called by the startup code or M_Responder,
// calls P_SetupLevel or W_EnterWorld.
void G_LoadGame (char* name);
void G_DoLoadGame (void);
// Called by M_Responder.
void G_SaveGame (int slot, char* description);
// Only called by startup code.
void G_RecordDemo (char* name);
void G_BeginRecording (void);
void G_PlayDemo (char* name);
void G_TimeDemo (char* name);
boolean G_CheckDemoStatus (void);
void G_ExitLevel (void);
void G_SecretExitLevel (void);
void G_WorldDone (void);
// Read current data from inputs and build a player movement command.
void G_BuildTiccmd (ticcmd_t *cmd, int maketic);
void G_Ticker (void);
boolean G_Responder (event_t* ev);
void G_ScreenShot (void);
void G_DrawMouseSpeedBox(void);
int G_VanillaVersionCode(void);
extern int vanilla_savegame_limit;
extern int vanilla_demo_limit;
#endif

265
apps/doom/gusconf.c Normal file
View File

@ -0,0 +1,265 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// GUS emulation code.
//
// Actually emulating a GUS is far too much work; fortunately
// GUS "emulation" already exists in the form of Timidity, which
// supports GUS patch files. This code therefore converts Doom's
// DMXGUS lump into an equivalent Timidity configuration file.
//
#include "essence/include.h"
#include "w_wad.h"
#include "z_zone.h"
#define MAX_INSTRUMENTS 256
typedef struct
{
char *patch_names[MAX_INSTRUMENTS];
int mapping[MAX_INSTRUMENTS];
} gus_config_t;
char *gus_patch_path = "";
unsigned int gus_ram_kb = 1024;
static unsigned int MappingIndex(void)
{
unsigned int result = gus_ram_kb / 256;
if (result < 1)
{
return 1;
}
else if (result > 4)
{
return 4;
}
else
{
return result;
}
}
static int SplitLine(char *line, char **fields, unsigned int max_fields)
{
unsigned int num_fields;
char *p;
fields[0] = line;
num_fields = 1;
for (p = line; *p != '\0'; ++p)
{
if (*p == ',')
{
*p = '\0';
// Skip spaces following the comma.
do
{
++p;
} while (*p != '\0' && ES_isspace(*p));
fields[num_fields] = p;
++num_fields;
--p;
if (num_fields >= max_fields)
{
break;
}
}
else if (*p == '#')
{
*p = '\0';
break;
}
}
// Strip off trailing whitespace from the end of the line.
p = fields[num_fields - 1] + ES_strlen(fields[num_fields - 1]);
while (p > fields[num_fields - 1] && ES_isspace(*(p - 1)))
{
--p;
*p = '\0';
}
return num_fields;
}
static void ParseLine(gus_config_t *config, char *line)
{
char *fields[6];
unsigned int num_fields;
unsigned int instr_id, mapped_id;
num_fields = SplitLine(line, fields, 6);
if (num_fields < 6)
{
return;
}
instr_id = ES_atoi(fields[0]);
mapped_id = ES_atoi(fields[MappingIndex()]);
ES_free(config->patch_names[instr_id]);
config->patch_names[instr_id] = ES_strdup(fields[5]);
config->mapping[instr_id] = mapped_id;
}
static void ParseDMXConfig(char *dmxconf, gus_config_t *config)
{
char *p, *newline;
unsigned int i;
ES_memset(config, 0, sizeof(gus_config_t));
for (i = 0; i < MAX_INSTRUMENTS; ++i)
{
config->mapping[i] = -1;
}
p = dmxconf;
for (;;)
{
newline = ES_strchr(p, '\n');
if (newline != NULL)
{
*newline = '\0';
}
ParseLine(config, p);
if (newline == NULL)
{
break;
}
else
{
p = newline + 1;
}
}
}
static void FreeDMXConfig(gus_config_t *config)
{
unsigned int i;
for (i = 0; i < MAX_INSTRUMENTS; ++i)
{
ES_free(config->patch_names[i]);
}
}
static char *ReadDMXConfig(void)
{
int lumpnum;
unsigned int len;
char *data;
// TODO: This should be chosen based on gamemode == commercial:
lumpnum = W_CheckNumForName("DMXGUS");
if (lumpnum < 0)
{
lumpnum = W_GetNumForName("DMXGUSC");
}
len = W_LumpLength(lumpnum);
data = Z_Malloc(len + 1, PU_STATIC, NULL);
W_ReadLump(lumpnum, data);
return data;
}
static boolean WriteTimidityConfig(char *path, gus_config_t *config)
{
ES_File *fstream;
unsigned int i;
fstream = ES_fopen(path, ES_WRITE_MODE);
if (fstream == NULL)
{
return false;
}
ES_fprintf(fstream, "# Autogenerated Timidity config.\n\n");
ES_fprintf(fstream, "dir %s\n", gus_patch_path);
ES_fprintf(fstream, "\nbank 0\n\n");
for (i = 0; i < 128; ++i)
{
if (config->mapping[i] >= 0 && config->mapping[i] < MAX_INSTRUMENTS
&& config->patch_names[config->mapping[i]] != NULL)
{
ES_fprintf(fstream, "%i %s\n",
i, config->patch_names[config->mapping[i]]);
}
}
ES_fprintf(fstream, "\ndrumset 0\n\n");
for (i = 128 + 25; i < MAX_INSTRUMENTS; ++i)
{
if (config->mapping[i] >= 0 && config->mapping[i] < MAX_INSTRUMENTS
&& config->patch_names[config->mapping[i]] != NULL)
{
ES_fprintf(fstream, "%i %s\n",
i - 128, config->patch_names[config->mapping[i]]);
}
}
ES_fprintf(fstream, "\n");
ES_fclose(fstream);
return true;
}
boolean GUS_WriteConfig(char *path)
{
boolean result;
char *dmxconf;
gus_config_t config;
if (!ES_strcmp(gus_patch_path, ""))
{
ES_warnf("You haven't configured gus_patch_path.\n");
ES_warnf("gus_patch_path needs to point to the location of "
"your GUS patch set.\n"
"To get a copy of the \"standard\" GUS patches, "
"download a copy of dgguspat.zip.\n");
return false;
}
dmxconf = ReadDMXConfig();
ParseDMXConfig(dmxconf, &config);
result = WriteTimidityConfig(path, &config);
FreeDMXConfig(&config);
Z_Free(dmxconf);
return result;
}

28
apps/doom/gusconf.h Normal file
View File

@ -0,0 +1,28 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// GUS emulation code.
//
#ifndef __GUSCONF_H__
#define __GUSCONF_H__
#include "doomtype.h"
extern char *gus_patch_path;
extern unsigned int gus_ram_kb;
boolean GUS_WriteConfig(char *path);
#endif /* #ifndef __GUSCONF_H__ */

345
apps/doom/hu_lib.c Normal file
View File

@ -0,0 +1,345 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION: heads-up text and input code
//
#include "essence/include.h"
#include "doomdef.h"
#include "doomkeys.h"
#include "v_video.h"
#include "i_swap.h"
#include "hu_lib.h"
#include "r_local.h"
#include "r_draw.h"
// boolean : whether the screen is always erased
#define noterased viewwindowx
extern boolean automapactive; // in AM_map.c
void HUlib_init(void)
{
}
void HUlib_clearTextLine(hu_textline_t* t)
{
t->len = 0;
t->l[0] = 0;
t->needsupdate = true;
}
void
HUlib_initTextLine
( hu_textline_t* t,
int x,
int y,
patch_t** f,
int sc )
{
t->x = x;
t->y = y;
t->f = f;
t->sc = sc;
HUlib_clearTextLine(t);
}
boolean
HUlib_addCharToTextLine
( hu_textline_t* t,
char ch )
{
if (t->len == HU_MAXLINELENGTH)
return false;
else
{
t->l[t->len++] = ch;
t->l[t->len] = 0;
t->needsupdate = 4;
return true;
}
}
boolean HUlib_delCharFromTextLine(hu_textline_t* t)
{
if (!t->len) return false;
else
{
t->l[--t->len] = 0;
t->needsupdate = 4;
return true;
}
}
void
HUlib_drawTextLine
( hu_textline_t* l,
boolean drawcursor )
{
int i;
int w;
int x;
unsigned char c;
// draw the new stuff
x = l->x;
for (i=0;i<l->len;i++)
{
c = ES_toupper((int)l->l[i]);
if (c != ' '
&& c >= l->sc
&& c <= '_')
{
w = SHORT(l->f[c - l->sc]->width);
if (x+w > SCREENWIDTH)
break;
V_DrawPatchDirect(x, l->y, l->f[c - l->sc]);
x += w;
}
else
{
x += 4;
if (x >= SCREENWIDTH)
break;
}
}
// draw the cursor if requested
if (drawcursor
&& x + SHORT(l->f['_' - l->sc]->width) <= SCREENWIDTH)
{
V_DrawPatchDirect(x, l->y, l->f['_' - l->sc]);
}
}
// sorta called by HU_Erase and just better darn get things straight
void HUlib_eraseTextLine(hu_textline_t* l)
{
int lh;
int y;
int yoffset;
// Only erases when NOT in automap and the screen is reduced,
// and the text must either need updating or refreshing
// (because of a recent change back from the automap)
if (!automapactive &&
viewwindowx && l->needsupdate)
{
lh = SHORT(l->f[0]->height) + 1;
for (y=l->y,yoffset=y*SCREENWIDTH ; y<l->y+lh ; y++,yoffset+=SCREENWIDTH)
{
if (y < viewwindowy || y >= viewwindowy + viewheight)
R_VideoErase(yoffset, SCREENWIDTH); // erase entire line
else
{
R_VideoErase(yoffset, viewwindowx); // erase left border
R_VideoErase(yoffset + viewwindowx + viewwidth, viewwindowx);
// erase right border
}
}
}
if (l->needsupdate) l->needsupdate--;
}
void
HUlib_initSText
( hu_stext_t* s,
int x,
int y,
int h,
patch_t** font,
int startchar,
boolean* on )
{
int i;
s->h = h;
s->on = on;
s->laston = true;
s->cl = 0;
for (i=0;i<h;i++)
HUlib_initTextLine(&s->l[i],
x, y - i*(SHORT(font[0]->height)+1),
font, startchar);
}
void HUlib_addLineToSText(hu_stext_t* s)
{
int i;
// add a clear line
if (++s->cl == s->h)
s->cl = 0;
HUlib_clearTextLine(&s->l[s->cl]);
// everything needs updating
for (i=0 ; i<s->h ; i++)
s->l[i].needsupdate = 4;
}
void
HUlib_addMessageToSText
( hu_stext_t* s,
char* prefix,
char* msg )
{
HUlib_addLineToSText(s);
if (prefix)
while (*prefix)
HUlib_addCharToTextLine(&s->l[s->cl], *(prefix++));
while (*msg)
HUlib_addCharToTextLine(&s->l[s->cl], *(msg++));
}
void HUlib_drawSText(hu_stext_t* s)
{
int i, idx;
hu_textline_t *l;
if (!*s->on)
return; // if not on, don't draw
// draw everything
for (i=0 ; i<s->h ; i++)
{
idx = s->cl - i;
if (idx < 0)
idx += s->h; // handle queue of lines
l = &s->l[idx];
// need a decision made here on whether to skip the draw
HUlib_drawTextLine(l, false); // no cursor, please
}
}
void HUlib_eraseSText(hu_stext_t* s)
{
int i;
for (i=0 ; i<s->h ; i++)
{
if (s->laston && !*s->on)
s->l[i].needsupdate = 4;
HUlib_eraseTextLine(&s->l[i]);
}
s->laston = *s->on;
}
void
HUlib_initIText
( hu_itext_t* it,
int x,
int y,
patch_t** font,
int startchar,
boolean* on )
{
it->lm = 0; // default left margin is start of text
it->on = on;
it->laston = true;
HUlib_initTextLine(&it->l, x, y, font, startchar);
}
// The following deletion routines adhere to the left margin restriction
void HUlib_delCharFromIText(hu_itext_t* it)
{
if (it->l.len != it->lm)
HUlib_delCharFromTextLine(&it->l);
}
void HUlib_eraseLineFromIText(hu_itext_t* it)
{
while (it->lm != it->l.len)
HUlib_delCharFromTextLine(&it->l);
}
// Resets left margin as well
void HUlib_resetIText(hu_itext_t* it)
{
it->lm = 0;
HUlib_clearTextLine(&it->l);
}
void
HUlib_addPrefixToIText
( hu_itext_t* it,
char* str )
{
while (*str)
HUlib_addCharToTextLine(&it->l, *(str++));
it->lm = it->l.len;
}
// wrapper function for handling general keyed input.
// returns true if it ate the key
boolean
HUlib_keyInIText
( hu_itext_t* it,
unsigned char ch )
{
ch = ES_toupper(ch);
if (ch >= ' ' && ch <= '_')
HUlib_addCharToTextLine(&it->l, (char) ch);
else
if (ch == KEY_BACKSPACE)
HUlib_delCharFromIText(it);
else
if (ch != KEY_ENTER)
return false; // did not eat key
return true; // ate the key
}
void HUlib_drawIText(hu_itext_t* it)
{
hu_textline_t *l = &it->l;
if (!*it->on)
return;
HUlib_drawTextLine(l, true); // draw the line w/ cursor
}
void HUlib_eraseIText(hu_itext_t* it)
{
if (it->laston && !*it->on)
it->l.needsupdate = 4;
HUlib_eraseTextLine(&it->l);
it->laston = *it->on;
}

182
apps/doom/hu_lib.h Normal file
View File

@ -0,0 +1,182 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION: none
//
#ifndef __HULIB__
#define __HULIB__
// We are referring to patches.
#include "r_defs.h"
// font stuff
#define HU_CHARERASE KEY_BACKSPACE
#define HU_MAXLINES 4
#define HU_MAXLINELENGTH 80
//
// Typedefs of widgets
//
// Text Line widget
// (parent of Scrolling Text and Input Text widgets)
typedef struct
{
// left-justified position of scrolling text window
int x;
int y;
patch_t** f; // font
int sc; // start character
char l[HU_MAXLINELENGTH+1]; // line of text
int len; // current line length
// whether this line needs to be udpated
int needsupdate;
} hu_textline_t;
// Scrolling Text window widget
// (child of Text Line widget)
typedef struct
{
hu_textline_t l[HU_MAXLINES]; // text lines to draw
int h; // height in lines
int cl; // current line number
// pointer to boolean stating whether to update window
boolean* on;
boolean laston; // last value of *->on.
} hu_stext_t;
// Input Text Line widget
// (child of Text Line widget)
typedef struct
{
hu_textline_t l; // text line to input on
// left margin past which I am not to delete characters
int lm;
// pointer to boolean stating whether to update window
boolean* on;
boolean laston; // last value of *->on;
} hu_itext_t;
//
// Widget creation, access, and update routines
//
// initializes heads-up widget library
void HUlib_init(void);
//
// textline code
//
// clear a line of text
void HUlib_clearTextLine(hu_textline_t *t);
void HUlib_initTextLine(hu_textline_t *t, int x, int y, patch_t **f, int sc);
// returns success
boolean HUlib_addCharToTextLine(hu_textline_t *t, char ch);
// returns success
boolean HUlib_delCharFromTextLine(hu_textline_t *t);
// draws tline
void HUlib_drawTextLine(hu_textline_t *l, boolean drawcursor);
// erases text line
void HUlib_eraseTextLine(hu_textline_t *l);
//
// Scrolling Text window widget routines
//
// ?
void
HUlib_initSText
( hu_stext_t* s,
int x,
int y,
int h,
patch_t** font,
int startchar,
boolean* on );
// add a new line
void HUlib_addLineToSText(hu_stext_t* s);
// ?
void
HUlib_addMessageToSText
( hu_stext_t* s,
char* prefix,
char* msg );
// draws stext
void HUlib_drawSText(hu_stext_t* s);
// erases all stext lines
void HUlib_eraseSText(hu_stext_t* s);
// Input Text Line widget routines
void
HUlib_initIText
( hu_itext_t* it,
int x,
int y,
patch_t** font,
int startchar,
boolean* on );
// enforces left margin
void HUlib_delCharFromIText(hu_itext_t* it);
// enforces left margin
void HUlib_eraseLineFromIText(hu_itext_t* it);
// resets line and left margin
void HUlib_resetIText(hu_itext_t* it);
// left of left-margin
void
HUlib_addPrefixToIText
( hu_itext_t* it,
char* str );
// whether eaten
boolean
HUlib_keyInIText
( hu_itext_t* it,
unsigned char ch );
void HUlib_drawIText(hu_itext_t* it);
// erases all itext lines
void HUlib_eraseIText(hu_itext_t* it);
#endif

631
apps/doom/hu_stuff.c Normal file
View File

@ -0,0 +1,631 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION: Heads-up displays
//
#include "essence/include.h"
#include "doomdef.h"
#include "doomkeys.h"
#include "z_zone.h"
#include "i_swap.h"
#include "i_video.h"
#include "hu_stuff.h"
#include "hu_lib.h"
#include "m_controls.h"
#include "m_misc.h"
#include "w_wad.h"
#include "s_sound.h"
#include "doomstat.h"
// Data.
#include "dstrings.h"
#include "sounds.h"
//
// Locally used constants, shortcuts.
//
#define HU_TITLE (mapnames[(gameepisode-1)*9+gamemap-1])
#define HU_TITLE2 (mapnames_commercial[gamemap-1])
#define HU_TITLEP (mapnames_commercial[gamemap-1 + 32])
#define HU_TITLET (mapnames_commercial[gamemap-1 + 64])
#define HU_TITLE_CHEX (mapnames[gamemap - 1])
#define HU_TITLEHEIGHT 1
#define HU_TITLEX 0
#define HU_TITLEY (167 - SHORT(hu_font[0]->height))
#define HU_INPUTTOGGLE 't'
#define HU_INPUTX HU_MSGX
#define HU_INPUTY (HU_MSGY + HU_MSGHEIGHT*(SHORT(hu_font[0]->height) +1))
#define HU_INPUTWIDTH 64
#define HU_INPUTHEIGHT 1
char *chat_macros[10] =
{
HUSTR_CHATMACRO0,
HUSTR_CHATMACRO1,
HUSTR_CHATMACRO2,
HUSTR_CHATMACRO3,
HUSTR_CHATMACRO4,
HUSTR_CHATMACRO5,
HUSTR_CHATMACRO6,
HUSTR_CHATMACRO7,
HUSTR_CHATMACRO8,
HUSTR_CHATMACRO9
};
char* player_names[] =
{
HUSTR_PLRGREEN,
HUSTR_PLRINDIGO,
HUSTR_PLRBROWN,
HUSTR_PLRRED
};
char chat_char; // remove later.
static player_t* plr;
patch_t* hu_font[HU_FONTSIZE];
static hu_textline_t w_title;
boolean chat_on;
static hu_itext_t w_chat;
static boolean always_off = false;
static char chat_dest[MAXPLAYERS];
static hu_itext_t w_inputbuffer[MAXPLAYERS];
static boolean message_on;
boolean message_dontfuckwithme;
static boolean message_nottobefuckedwith;
static hu_stext_t w_message;
static int message_counter;
extern int showMessages;
static boolean headsupactive = false;
//
// Builtin map names.
// The actual names can be found in DStrings.h.
//
char* mapnames[] = // DOOM shareware/registered/retail (Ultimate) names.
{
HUSTR_E1M1,
HUSTR_E1M2,
HUSTR_E1M3,
HUSTR_E1M4,
HUSTR_E1M5,
HUSTR_E1M6,
HUSTR_E1M7,
HUSTR_E1M8,
HUSTR_E1M9,
HUSTR_E2M1,
HUSTR_E2M2,
HUSTR_E2M3,
HUSTR_E2M4,
HUSTR_E2M5,
HUSTR_E2M6,
HUSTR_E2M7,
HUSTR_E2M8,
HUSTR_E2M9,
HUSTR_E3M1,
HUSTR_E3M2,
HUSTR_E3M3,
HUSTR_E3M4,
HUSTR_E3M5,
HUSTR_E3M6,
HUSTR_E3M7,
HUSTR_E3M8,
HUSTR_E3M9,
HUSTR_E4M1,
HUSTR_E4M2,
HUSTR_E4M3,
HUSTR_E4M4,
HUSTR_E4M5,
HUSTR_E4M6,
HUSTR_E4M7,
HUSTR_E4M8,
HUSTR_E4M9,
"NEWLEVEL",
"NEWLEVEL",
"NEWLEVEL",
"NEWLEVEL",
"NEWLEVEL",
"NEWLEVEL",
"NEWLEVEL",
"NEWLEVEL",
"NEWLEVEL"
};
// List of names for levels in commercial IWADs
// (doom2.wad, plutonia.wad, tnt.wad). These are stored in a
// single large array; WADs like pl2.wad have a MAP33, and rely on
// the layout in the Vanilla executable, where it is possible to
// overflow the end of one array into the next.
char *mapnames_commercial[] =
{
// DOOM 2 map names.
HUSTR_1,
HUSTR_2,
HUSTR_3,
HUSTR_4,
HUSTR_5,
HUSTR_6,
HUSTR_7,
HUSTR_8,
HUSTR_9,
HUSTR_10,
HUSTR_11,
HUSTR_12,
HUSTR_13,
HUSTR_14,
HUSTR_15,
HUSTR_16,
HUSTR_17,
HUSTR_18,
HUSTR_19,
HUSTR_20,
HUSTR_21,
HUSTR_22,
HUSTR_23,
HUSTR_24,
HUSTR_25,
HUSTR_26,
HUSTR_27,
HUSTR_28,
HUSTR_29,
HUSTR_30,
HUSTR_31,
HUSTR_32,
// Plutonia WAD map names.
PHUSTR_1,
PHUSTR_2,
PHUSTR_3,
PHUSTR_4,
PHUSTR_5,
PHUSTR_6,
PHUSTR_7,
PHUSTR_8,
PHUSTR_9,
PHUSTR_10,
PHUSTR_11,
PHUSTR_12,
PHUSTR_13,
PHUSTR_14,
PHUSTR_15,
PHUSTR_16,
PHUSTR_17,
PHUSTR_18,
PHUSTR_19,
PHUSTR_20,
PHUSTR_21,
PHUSTR_22,
PHUSTR_23,
PHUSTR_24,
PHUSTR_25,
PHUSTR_26,
PHUSTR_27,
PHUSTR_28,
PHUSTR_29,
PHUSTR_30,
PHUSTR_31,
PHUSTR_32,
// TNT WAD map names.
THUSTR_1,
THUSTR_2,
THUSTR_3,
THUSTR_4,
THUSTR_5,
THUSTR_6,
THUSTR_7,
THUSTR_8,
THUSTR_9,
THUSTR_10,
THUSTR_11,
THUSTR_12,
THUSTR_13,
THUSTR_14,
THUSTR_15,
THUSTR_16,
THUSTR_17,
THUSTR_18,
THUSTR_19,
THUSTR_20,
THUSTR_21,
THUSTR_22,
THUSTR_23,
THUSTR_24,
THUSTR_25,
THUSTR_26,
THUSTR_27,
THUSTR_28,
THUSTR_29,
THUSTR_30,
THUSTR_31,
THUSTR_32
};
void HU_Init(void)
{
int i;
int j;
char buffer[9];
// load the heads-up font
j = HU_FONTSTART;
for (i=0;i<HU_FONTSIZE;i++)
{
M_snprintf(buffer, 9, "STCFN%.3d", j++);
hu_font[i] = (patch_t *) W_CacheLumpName(buffer, PU_STATIC);
}
}
void HU_Stop(void)
{
headsupactive = false;
}
void HU_Start(void)
{
int i;
char* s;
if (headsupactive)
HU_Stop();
plr = &players[consoleplayer];
message_on = false;
message_dontfuckwithme = false;
message_nottobefuckedwith = false;
chat_on = false;
// create the message widget
HUlib_initSText(&w_message,
HU_MSGX, HU_MSGY, HU_MSGHEIGHT,
hu_font,
HU_FONTSTART, &message_on);
// create the map title widget
HUlib_initTextLine(&w_title,
HU_TITLEX, HU_TITLEY,
hu_font,
HU_FONTSTART);
switch ( logical_gamemission )
{
case doom:
s = HU_TITLE;
break;
case doom2:
s = HU_TITLE2;
break;
case pack_plut:
s = HU_TITLEP;
break;
case pack_tnt:
s = HU_TITLET;
break;
default:
s = "Unknown level";
break;
}
// Chex.exe always uses the episode 1 level title
// eg. E2M1 gives the title for E1M1
if (gameversion == exe_chex)
{
s = HU_TITLE_CHEX;
}
while (*s)
HUlib_addCharToTextLine(&w_title, *(s++));
// create the chat widget
HUlib_initIText(&w_chat,
HU_INPUTX, HU_INPUTY,
hu_font,
HU_FONTSTART, &chat_on);
// create the inputbuffer widgets
for (i=0 ; i<MAXPLAYERS ; i++)
HUlib_initIText(&w_inputbuffer[i], 0, 0, 0, 0, &always_off);
headsupactive = true;
}
void HU_Drawer(void)
{
HUlib_drawSText(&w_message);
HUlib_drawIText(&w_chat);
if (automapactive)
HUlib_drawTextLine(&w_title, false);
}
void HU_Erase(void)
{
HUlib_eraseSText(&w_message);
HUlib_eraseIText(&w_chat);
HUlib_eraseTextLine(&w_title);
}
void HU_Ticker(void)
{
int i, rc;
char c;
// tick down message counter if message is up
if (message_counter && !--message_counter)
{
message_on = false;
message_nottobefuckedwith = false;
}
if (showMessages || message_dontfuckwithme)
{
// display message if necessary
if ((plr->message && !message_nottobefuckedwith)
|| (plr->message && message_dontfuckwithme))
{
HUlib_addMessageToSText(&w_message, 0, plr->message);
plr->message = 0;
message_on = true;
message_counter = HU_MSGTIMEOUT;
message_nottobefuckedwith = message_dontfuckwithme;
message_dontfuckwithme = 0;
}
} // else message_on = false;
// check for incoming chat characters
if (netgame)
{
for (i=0 ; i<MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
if (i != consoleplayer
&& (c = players[i].cmd.chatchar))
{
if (c <= HU_BROADCAST)
chat_dest[i] = c;
else
{
rc = HUlib_keyInIText(&w_inputbuffer[i], c);
if (rc && c == KEY_ENTER)
{
if (w_inputbuffer[i].l.len
&& (chat_dest[i] == consoleplayer+1
|| chat_dest[i] == HU_BROADCAST))
{
HUlib_addMessageToSText(&w_message,
player_names[i],
w_inputbuffer[i].l.l);
message_nottobefuckedwith = true;
message_on = true;
message_counter = HU_MSGTIMEOUT;
if ( gamemode == commercial )
S_StartSound(0, sfx_radio);
else
S_StartSound(0, sfx_tink);
}
HUlib_resetIText(&w_inputbuffer[i]);
}
}
players[i].cmd.chatchar = 0;
}
}
}
}
#define QUEUESIZE 128
static char chatchars[QUEUESIZE];
static int head = 0;
static int tail = 0;
void HU_queueChatChar(char c)
{
if (((head + 1) & (QUEUESIZE-1)) == tail)
{
plr->message = HUSTR_MSGU;
}
else
{
chatchars[head] = c;
head = (head + 1) & (QUEUESIZE-1);
}
}
char HU_dequeueChatChar(void)
{
char c;
if (head != tail)
{
c = chatchars[tail];
tail = (tail + 1) & (QUEUESIZE-1);
}
else
{
c = 0;
}
return c;
}
boolean HU_Responder(event_t *ev)
{
static char lastmessage[HU_MAXLINELENGTH+1];
char* macromessage;
boolean eatkey = false;
static boolean altdown = false;
unsigned char c;
int i;
int numplayers;
static int num_nobrainers = 0;
numplayers = 0;
for (i=0 ; i<MAXPLAYERS ; i++)
numplayers += playeringame[i];
if (ev->data1 == KEY_RSHIFT)
{
return false;
}
else if (ev->data1 == KEY_RALT || ev->data1 == KEY_LALT)
{
altdown = ev->type == ev_keydown;
return false;
}
if (ev->type != ev_keydown)
return false;
if (!chat_on)
{
if (ev->data1 == key_message_refresh)
{
message_on = true;
message_counter = HU_MSGTIMEOUT;
eatkey = true;
}
else if (netgame && ev->data2 == key_multi_msg)
{
eatkey = chat_on = true;
HUlib_resetIText(&w_chat);
HU_queueChatChar(HU_BROADCAST);
}
else if (netgame && numplayers > 2)
{
for (i=0; i<MAXPLAYERS ; i++)
{
if (ev->data2 == key_multi_msgplayer[i])
{
if (playeringame[i] && i!=consoleplayer)
{
eatkey = chat_on = true;
HUlib_resetIText(&w_chat);
HU_queueChatChar(i+1);
break;
}
else if (i == consoleplayer)
{
num_nobrainers++;
if (num_nobrainers < 3)
plr->message = HUSTR_TALKTOSELF1;
else if (num_nobrainers < 6)
plr->message = HUSTR_TALKTOSELF2;
else if (num_nobrainers < 9)
plr->message = HUSTR_TALKTOSELF3;
else if (num_nobrainers < 32)
plr->message = HUSTR_TALKTOSELF4;
else
plr->message = HUSTR_TALKTOSELF5;
}
}
}
}
}
else
{
// send a macro
if (altdown)
{
c = ev->data1 - '0';
if (c > 9)
return false;
macromessage = chat_macros[c];
// kill last message with a '\n'
HU_queueChatChar(KEY_ENTER); // DEBUG!!!
// send the macro message
while (*macromessage)
HU_queueChatChar(*macromessage++);
HU_queueChatChar(KEY_ENTER);
// leave chat mode and notify that it was sent
chat_on = false;
M_StringCopy(lastmessage, chat_macros[c], sizeof(lastmessage));
plr->message = lastmessage;
eatkey = true;
}
else
{
c = ev->data2;
eatkey = HUlib_keyInIText(&w_chat, c);
if (eatkey)
{
// static unsigned char buf[20]; // DEBUG
HU_queueChatChar(c);
}
if (c == KEY_ENTER)
{
chat_on = false;
if (w_chat.l.len)
{
M_StringCopy(lastmessage, w_chat.l.l, sizeof(lastmessage));
plr->message = lastmessage;
}
}
else if (c == KEY_ESCAPE)
chat_on = false;
}
}
return eatkey;
}

57
apps/doom/hu_stuff.h Normal file
View File

@ -0,0 +1,57 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION: Head up display
//
#ifndef __HU_STUFF_H__
#define __HU_STUFF_H__
#include "d_event.h"
//
// Globally visible constants.
//
#define HU_FONTSTART '!' // the first font characters
#define HU_FONTEND '_' // the last font characters
// Calculate # of glyphs in font.
#define HU_FONTSIZE (HU_FONTEND - HU_FONTSTART + 1)
#define HU_BROADCAST 5
#define HU_MSGX 0
#define HU_MSGY 0
#define HU_MSGWIDTH 64 // in characters
#define HU_MSGHEIGHT 1 // in lines
#define HU_MSGTIMEOUT (4*TICRATE)
//
// HEADS UP TEXT
//
void HU_Init(void);
void HU_Start(void);
boolean HU_Responder(event_t* ev);
void HU_Ticker(void);
void HU_Drawer(void);
char HU_dequeueChatChar(void);
void HU_Erase(void);
extern char *chat_macros[10];
#endif

172
apps/doom/i_input.c Normal file
View File

@ -0,0 +1,172 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include "essence/include.h"
#include "config.h"
#include "doomtype.h"
#include "doomkeys.h"
#include "i_joystick.h"
#include "i_system.h"
#include "i_swap.h"
#include "i_timer.h"
#include "i_video.h"
#include "i_scale.h"
#include "m_argv.h"
#include "m_config.h"
#include "m_misc.h"
#include "tables.h"
#include "v_video.h"
#include "w_wad.h"
#include "z_zone.h"
int vanilla_keyboard_mapping = 1;
// Is the shift key currently down?
static int shiftdown = 0;
// Lookup table for mapping ASCII characters to their equivalent when
// shift is pressed on an American layout keyboard:
static const char shiftxform[] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, ' ', '!', '"', '#', '$', '%', '&',
'"', // shift-'
'(', ')', '*', '+',
'<', // shift-,
'_', // shift--
'>', // shift-.
'?', // shift-/
')', // shift-0
'!', // shift-1
'@', // shift-2
'#', // shift-3
'$', // shift-4
'%', // shift-5
'^', // shift-6
'&', // shift-7
'*', // shift-8
'(', // shift-9
':',
':', // shift-;
'<',
'+', // shift-=
'>', '?', '@',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'[', // shift-[
'!', // shift-backslash - OH MY GOD DOES WATCOM SUCK
']', // shift-]
'"', '_',
'\'', // shift-`
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'{', '|', '}', '~', 127
};
static unsigned char TranslateKey(unsigned char key)
{
return key;
}
// Get the equivalent ASCII (Unicode?) character for a keypress.
static unsigned char GetTypedChar(unsigned char key)
{
key = TranslateKey(key);
// Is shift held down? If so, perform a translation.
if (shiftdown > 0)
{
if (key >= 0 && key < arrlen(shiftxform))
{
key = shiftxform[key];
}
else
{
key = 0;
}
}
return key;
}
static void UpdateShiftStatus(int pressed, unsigned char key)
{
int change;
if (pressed) {
change = 1;
} else {
change = -1;
}
if (key == KEY_RSHIFT) {
shiftdown += change;
}
}
void I_GetEvent(void)
{
event_t event;
int pressed;
unsigned char key;
while (ES_GetKey(&pressed, &key))
{
UpdateShiftStatus(pressed, key);
// process event
if (pressed)
{
// data1 has the key pressed, data2 has the character
// (shift-translated, etc)
event.type = ev_keydown;
event.data1 = TranslateKey(key);
event.data2 = GetTypedChar(key);
if (event.data1 != 0)
{
D_PostEvent(&event);
}
}
else
{
event.type = ev_keyup;
event.data1 = TranslateKey(key);
// data2 is just initialized to zero for ev_keyup.
// For ev_keydown it's the shifted Unicode character
// that was typed, but if something wants to detect
// key releases it should do so based on data1
// (key ID), not the printable char.
event.data2 = 0;
if (event.data1 != 0)
{
D_PostEvent(&event);
}
}
}
}
void I_InitInput(void)
{}

92
apps/doom/i_joystick.c Normal file
View File

@ -0,0 +1,92 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// SDL Joystick code.
//
#include "doomtype.h"
#include "d_event.h"
#include "i_joystick.h"
#include "i_system.h"
#include "m_config.h"
#include "m_misc.h"
// When an axis is within the dead zone, it is set to zero.
// This is 5% of the full range:
#define DEAD_ZONE (32768 / 3)
// Configuration variables:
// Standard default.cfg Joystick enable/disable
static int usejoystick = 0;
// Joystick to use, as an SDL joystick index:
static int joystick_index = -1;
// Which joystick axis to use for horizontal movement, and whether to
// invert the direction:
static int joystick_x_axis = 0;
static int joystick_x_invert = 0;
// Which joystick axis to use for vertical movement, and whether to
// invert the direction:
static int joystick_y_axis = 1;
static int joystick_y_invert = 0;
// Which joystick axis to use for strafing?
static int joystick_strafe_axis = -1;
static int joystick_strafe_invert = 0;
// Virtual to physical button joystick button mapping. By default this
// is a straight mapping.
static int joystick_physical_buttons[NUM_VIRTUAL_BUTTONS] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
};
void I_ShutdownJoystick(void)
{}
void I_InitJoystick(void)
{}
void I_UpdateJoystick(void)
{}
void I_BindJoystickVariables(void)
{
int i;
M_BindVariable("use_joystick", &usejoystick);
M_BindVariable("joystick_index", &joystick_index);
M_BindVariable("joystick_x_axis", &joystick_x_axis);
M_BindVariable("joystick_y_axis", &joystick_y_axis);
M_BindVariable("joystick_strafe_axis", &joystick_strafe_axis);
M_BindVariable("joystick_x_invert", &joystick_x_invert);
M_BindVariable("joystick_y_invert", &joystick_y_invert);
M_BindVariable("joystick_strafe_invert",&joystick_strafe_invert);
for (i = 0; i < NUM_VIRTUAL_BUTTONS; ++i)
{
char name[32];
M_snprintf(name, sizeof(name), "joystick_physical_button%i", i);
M_BindVariable(name, &joystick_physical_buttons[i]);
}
}

69
apps/doom/i_joystick.h Normal file
View File

@ -0,0 +1,69 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// System-specific joystick interface.
//
#ifndef __I_JOYSTICK__
#define __I_JOYSTICK__
// Number of "virtual" joystick buttons defined in configuration files.
// This needs to be at least as large as the number of different key
// bindings supported by the higher-level game code (joyb* variables).
#define NUM_VIRTUAL_BUTTONS 10
// If this bit is set in a configuration file axis value, the axis is
// not actually a joystick axis, but instead is a "button axis". This
// means that instead of reading an SDL joystick axis, we read the
// state of two buttons to get the axis value. This is needed for eg.
// the PS3 SIXAXIS controller, where the D-pad buttons register as
// buttons, not as two axes.
#define BUTTON_AXIS 0x10000
// Query whether a given axis value describes a button axis.
#define IS_BUTTON_AXIS(axis) ((axis) >= 0 && ((axis) & BUTTON_AXIS) != 0)
// Get the individual buttons from a button axis value.
#define BUTTON_AXIS_NEG(axis) ((axis) & 0xff)
#define BUTTON_AXIS_POS(axis) (((axis) >> 8) & 0xff)
// Create a button axis value from two button values.
#define CREATE_BUTTON_AXIS(neg, pos) (BUTTON_AXIS | (neg) | ((pos) << 8))
// If this bit is set in an axis value, the axis is not actually a
// joystick axis, but is a "hat" axis. This means that we read (one of)
// the hats on the joystick.
#define HAT_AXIS 0x20000
#define IS_HAT_AXIS(axis) ((axis) >= 0 && ((axis) & HAT_AXIS) != 0)
// Get the hat number from a hat axis value.
#define HAT_AXIS_HAT(axis) ((axis) & 0xff)
// Which axis of the hat? (horizonal or vertical)
#define HAT_AXIS_DIRECTION(axis) (((axis) >> 8) & 0xff)
#define CREATE_HAT_AXIS(hat, direction) \
(HAT_AXIS | (hat) | ((direction) << 8))
#define HAT_AXIS_HORIZONTAL 1
#define HAT_AXIS_VERTICAL 2
void I_InitJoystick(void);
void I_ShutdownJoystick(void);
void I_UpdateJoystick(void);
void I_BindJoystickVariables(void);
#endif /* #ifndef __I_JOYSTICK__ */

1446
apps/doom/i_scale.c Normal file

File diff suppressed because it is too large Load Diff

52
apps/doom/i_scale.h Normal file
View File

@ -0,0 +1,52 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Pixel-doubling scale up functions.
//
#ifndef __I_SCALE__
#define __I_SCALE__
#include "doomtype.h"
void I_InitScale(byte *_src_buffer, byte *_dest_buffer, int _dest_pitch);
void I_ResetScaleTables(byte *palette);
// Scaled modes (direct multiples of 320x200)
extern screen_mode_t mode_scale_1x;
extern screen_mode_t mode_scale_2x;
extern screen_mode_t mode_scale_3x;
extern screen_mode_t mode_scale_4x;
extern screen_mode_t mode_scale_5x;
// Vertically stretched modes (320x200 -> multiples of 320x240)
extern screen_mode_t mode_stretch_1x;
extern screen_mode_t mode_stretch_2x;
extern screen_mode_t mode_stretch_3x;
extern screen_mode_t mode_stretch_4x;
extern screen_mode_t mode_stretch_5x;
// Horizontally squashed modes (320x200 -> multiples of 256x200)
extern screen_mode_t mode_squash_1x;
extern screen_mode_t mode_squash_2x;
extern screen_mode_t mode_squash_3x;
extern screen_mode_t mode_squash_4x;
extern screen_mode_t mode_squash_5x;
#endif /* #ifndef __I_SCALE__ */

397
apps/doom/i_sound.c Normal file
View File

@ -0,0 +1,397 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION: none
//
#include "essence/include.h"
#include "config.h"
#include "config.h"
#include "doomtype.h"
#include "i_sound.h"
#include "i_video.h"
#include "m_argv.h"
#include "m_config.h"
// Sound sample rate to use for digital output (Hz)
int snd_samplerate = 44100;
// Maximum number of bytes to dedicate to allocated sound effects.
// (Default: 64MB)
int snd_cachesize = 64 * 1024 * 1024;
// Config variable that controls the sound buffer size.
// We default to 28ms (1000 / 35fps = 1 buffer per tic).
int snd_maxslicetime_ms = 28;
// External command to invoke to play back music.
char *snd_musiccmd = "";
// Low-level sound and music modules we are using
static sound_module_t *sound_module = NULL;
static music_module_t *music_module = NULL;
int snd_musicdevice = SNDDEVICE_SB;
int snd_sfxdevice = SNDDEVICE_SB;
// DOS-specific options: These are unused but should be maintained
// so that the config file can be shared between chocolate
// doom and doom.exe
static int snd_sbport = 0;
static int snd_sbirq = 0;
static int snd_sbdma = 0;
static int snd_mport = 0;
// Compiled-in sound modules:
static sound_module_t *sound_modules[] =
{
#ifdef FEATURE_SOUND
&ES_sound_module,
#endif
NULL,
};
// Check if a sound device is in the given list of devices
static boolean SndDeviceInList(snddevice_t device, snddevice_t *list,
int len)
{
int i;
for (i=0; i<len; ++i)
{
if (device == list[i])
{
return true;
}
}
return false;
}
// Find and initialize a sound_module_t appropriate for the setting
// in snd_sfxdevice.
static void InitSfxModule(boolean use_sfx_prefix)
{
int i;
sound_module = NULL;
for (i=0; sound_modules[i] != NULL; ++i)
{
// Is the sfx device in the list of devices supported by
// this module?
if (SndDeviceInList(snd_sfxdevice,
sound_modules[i]->sound_devices,
sound_modules[i]->num_sound_devices))
{
// Initialize the module
if (sound_modules[i]->Init(use_sfx_prefix))
{
sound_module = sound_modules[i];
return;
}
}
}
}
// Initialize music according to snd_musicdevice.
static void InitMusicModule(void)
{
#ifdef FEATURE_SOUND
music_module = &ES_music_module;
#endif /* FEATURE_SOUND */
}
//
// Initializes sound stuff, including volume
// Sets channels, SFX and music volume,
// allocates channel buffer, sets S_sfx lookup.
//
void I_InitSound(boolean use_sfx_prefix)
{
boolean nosound, nosfx, nomusic;
//!
// @vanilla
//
// Disable all sound output.
//
nosound = M_CheckParm("-nosound") > 0;
//!
// @vanilla
//
// Disable sound effects.
//
nosfx = M_CheckParm("-nosfx") > 0;
//!
// @vanilla
//
// Disable music.
//
nomusic = M_CheckParm("-nomusic") > 0;
// Initialize the sound and music subsystems.
if (!nosound && !screensaver_mode)
{
if (!nosfx)
{
InitSfxModule(use_sfx_prefix);
}
if (!nomusic)
{
InitMusicModule();
}
}
}
void I_ShutdownSound(void)
{
if (sound_module != NULL)
{
sound_module->Shutdown();
}
if (music_module != NULL)
{
music_module->Shutdown();
}
}
int I_GetSfxLumpNum(sfxinfo_t *sfxinfo)
{
if (sound_module != NULL)
{
return sound_module->GetSfxLumpNum(sfxinfo);
}
else
{
return 0;
}
}
void I_UpdateSound(void)
{
if (sound_module != NULL)
{
sound_module->Update();
}
if (music_module != NULL && music_module->Poll != NULL)
{
music_module->Poll();
}
}
static void CheckVolumeSeparation(int *vol, int *sep)
{
if (*sep < 0)
{
*sep = 0;
}
else if (*sep > 254)
{
*sep = 254;
}
if (*vol < 0)
{
*vol = 0;
}
else if (*vol > 127)
{
*vol = 127;
}
}
void I_UpdateSoundParams(int channel, int vol, int sep)
{
if (sound_module != NULL)
{
CheckVolumeSeparation(&vol, &sep);
sound_module->UpdateSoundParams(channel, vol, sep);
}
}
int I_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep)
{
if (sound_module != NULL)
{
CheckVolumeSeparation(&vol, &sep);
return sound_module->StartSound(sfxinfo, channel, vol, sep);
}
else
{
return 0;
}
}
void I_StopSound(int channel)
{
if (sound_module != NULL)
{
sound_module->StopSound(channel);
}
}
boolean I_SoundIsPlaying(int channel)
{
if (sound_module != NULL)
{
return sound_module->SoundIsPlaying(channel);
}
else
{
return false;
}
}
void I_PrecacheSounds(sfxinfo_t *sounds, int num_sounds)
{
if (sound_module != NULL && sound_module->CacheSounds != NULL)
{
sound_module->CacheSounds(sounds, num_sounds);
}
}
void I_InitMusic(void)
{
if(music_module != NULL)
{
music_module->Init();
}
}
void I_ShutdownMusic(void)
{
}
void I_SetMusicVolume(int volume)
{
if (music_module != NULL)
{
music_module->SetMusicVolume(volume);
}
}
void I_PauseSong(void)
{
if (music_module != NULL)
{
music_module->PauseMusic();
}
}
void I_ResumeSong(void)
{
if (music_module != NULL)
{
music_module->ResumeMusic();
}
}
void *I_RegisterSong(void *data, int len)
{
if (music_module != NULL)
{
return music_module->RegisterSong(data, len);
}
else
{
return NULL;
}
}
void I_UnRegisterSong(void *handle)
{
if (music_module != NULL)
{
music_module->UnRegisterSong(handle);
}
}
void I_PlaySong(void *handle, boolean looping)
{
if (music_module != NULL)
{
music_module->PlaySong(handle, looping);
}
}
void I_StopSong(void)
{
if (music_module != NULL)
{
music_module->StopSong();
}
}
boolean I_MusicIsPlaying(void)
{
if (music_module != NULL)
{
return music_module->MusicIsPlaying();
}
else
{
return false;
}
}
void I_BindSoundVariables(void)
{
extern int use_libsamplerate;
extern float libsamplerate_scale;
M_BindVariable("snd_musicdevice", &snd_musicdevice);
M_BindVariable("snd_sfxdevice", &snd_sfxdevice);
M_BindVariable("snd_sbport", &snd_sbport);
M_BindVariable("snd_sbirq", &snd_sbirq);
M_BindVariable("snd_sbdma", &snd_sbdma);
M_BindVariable("snd_mport", &snd_mport);
M_BindVariable("snd_maxslicetime_ms", &snd_maxslicetime_ms);
M_BindVariable("snd_musiccmd", &snd_musiccmd);
M_BindVariable("snd_samplerate", &snd_samplerate);
M_BindVariable("snd_cachesize", &snd_cachesize);
#ifdef FEATURE_SOUND
M_BindVariable("use_libsamplerate", &use_libsamplerate);
M_BindVariable("libsamplerate_scale", &libsamplerate_scale);
#endif
}

255
apps/doom/i_sound.h Normal file
View File

@ -0,0 +1,255 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// The not so system specific sound interface.
//
#ifndef __I_SOUND__
#define __I_SOUND__
#include "doomtype.h"
//
// SoundFX struct.
//
typedef struct sfxinfo_struct sfxinfo_t;
struct sfxinfo_struct
{
// tag name, used for hexen.
char *tagname;
// lump name. If we are running with use_sfx_prefix=true, a
// 'DS' (or 'DP' for PC speaker sounds) is prepended to this.
char name[9];
// Sfx priority
int priority;
// referenced sound if a link
sfxinfo_t *link;
// pitch if a link
int pitch;
// volume if a link
int volume;
// this is checked every second to see if sound
// can be thrown out (if 0, then decrement, if -1,
// then throw out, if > 0, then it is in use)
int usefulness;
// lump number of sfx
int lumpnum;
// Maximum number of channels that the sound can be played on
// (Heretic)
int numchannels;
// data used by the low level code
void *driver_data;
};
//
// MusicInfo struct.
//
typedef struct
{
// up to 6-character name
char *name;
// lump number of music
int lumpnum;
// music data
void *data;
// music handle once registered
void *handle;
} musicinfo_t;
typedef enum
{
SNDDEVICE_NONE = 0,
SNDDEVICE_PCSPEAKER = 1,
SNDDEVICE_ADLIB = 2,
SNDDEVICE_SB = 3,
SNDDEVICE_PAS = 4,
SNDDEVICE_GUS = 5,
SNDDEVICE_WAVEBLASTER = 6,
SNDDEVICE_SOUNDCANVAS = 7,
SNDDEVICE_GENMIDI = 8,
SNDDEVICE_AWE32 = 9,
SNDDEVICE_CD = 10,
} snddevice_t;
// Interface for sound modules
typedef struct
{
// List of sound devices that this sound module is used for.
snddevice_t *sound_devices;
int num_sound_devices;
// Initialise sound module
// Returns true if successfully initialised
boolean (*Init)(boolean use_sfx_prefix);
// Shutdown sound module
void (*Shutdown)(void);
// Returns the lump index of the given sound.
int (*GetSfxLumpNum)(sfxinfo_t *sfxinfo);
// Called periodically to update the subsystem.
void (*Update)(void);
// Update the sound settings on the given channel.
void (*UpdateSoundParams)(int channel, int vol, int sep);
// Start a sound on a given channel. Returns the channel id
// or -1 on failure.
int (*StartSound)(sfxinfo_t *sfxinfo, int channel, int vol, int sep);
// Stop the sound playing on the given channel.
void (*StopSound)(int channel);
// Query if a sound is playing on the given channel
boolean (*SoundIsPlaying)(int channel);
// Called on startup to precache sound effects (if necessary)
void (*CacheSounds)(sfxinfo_t *sounds, int num_sounds);
} sound_module_t;
void I_InitSound(boolean use_sfx_prefix);
void I_ShutdownSound(void);
int I_GetSfxLumpNum(sfxinfo_t *sfxinfo);
void I_UpdateSound(void);
void I_UpdateSoundParams(int channel, int vol, int sep);
int I_StartSound(sfxinfo_t *sfxinfo, int channel, int vol, int sep);
void I_StopSound(int channel);
boolean I_SoundIsPlaying(int channel);
void I_PrecacheSounds(sfxinfo_t *sounds, int num_sounds);
// Interface for music modules
typedef struct
{
// List of sound devices that this music module is used for.
snddevice_t *sound_devices;
int num_sound_devices;
// Initialise the music subsystem
boolean (*Init)(void);
// Shutdown the music subsystem
void (*Shutdown)(void);
// Set music volume - range 0-127
void (*SetMusicVolume)(int volume);
// Pause music
void (*PauseMusic)(void);
// Un-pause music
void (*ResumeMusic)(void);
// Register a song handle from data
// Returns a handle that can be used to play the song
void *(*RegisterSong)(void *data, int len);
// Un-register (free) song data
void (*UnRegisterSong)(void *handle);
// Play the song
void (*PlaySong)(void *handle, boolean looping);
// Stop playing the current song.
void (*StopSong)(void);
// Query if music is playing.
boolean (*MusicIsPlaying)(void);
// Invoked periodically to poll.
void (*Poll)(void);
} music_module_t;
void I_InitMusic(void);
void I_ShutdownMusic(void);
void I_SetMusicVolume(int volume);
void I_PauseSong(void);
void I_ResumeSong(void);
void *I_RegisterSong(void *data, int len);
void I_UnRegisterSong(void *handle);
void I_PlaySong(void *handle, boolean looping);
void I_StopSong(void);
boolean I_MusicIsPlaying(void);
extern int snd_sfxdevice;
extern int snd_musicdevice;
extern int snd_samplerate;
extern int snd_cachesize;
extern int snd_maxslicetime_ms;
extern char *snd_musiccmd;
void I_BindSoundVariables(void);
// Sound modules
void I_InitTimidityConfig(void);
#ifdef FEATURE_SOUND
extern sound_module_t ES_sound_module;
extern music_module_t ES_music_module;
#endif
extern sound_module_t sound_pcsound_module;
extern music_module_t music_opl_module;
// For OPL module:
extern int opl_io_port;
// For native music module:
extern char *timidity_cfg_path;
#endif

28
apps/doom/i_swap.h Normal file
View File

@ -0,0 +1,28 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Endianess handling, swapping 16bit and 32bit.
//
#ifndef __I_SWAP__
#define __I_SWAP__
#define SHORT(x) ((signed short) (x))
#define LONG(x) ((signed int) (x))
#define SYS_LITTLE_ENDIAN
#endif

349
apps/doom/i_system.c Normal file
View File

@ -0,0 +1,349 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
//
#include "essence/include.h"
#include "config.h"
#include "doomtype.h"
#include "m_argv.h"
#include "m_config.h"
#include "m_misc.h"
#include "i_joystick.h"
#include "i_sound.h"
#include "i_timer.h"
#include "i_video.h"
#include "i_system.h"
#include "w_wad.h"
#include "z_zone.h"
#define DEFAULT_RAM 16 /* MiB */
#define MIN_RAM 16 /* MiB */
typedef struct atexit_listentry_s atexit_listentry_t;
struct atexit_listentry_s
{
atexit_func_t func;
boolean run_on_error;
atexit_listentry_t *next;
};
static atexit_listentry_t *exit_funcs = NULL;
void I_AtExit(atexit_func_t func, boolean run_on_error)
{
atexit_listentry_t *entry;
entry = ES_malloc(sizeof(*entry));
entry->func = func;
entry->run_on_error = run_on_error;
entry->next = exit_funcs;
exit_funcs = entry;
}
// Tactile feedback function, probably used for the Logitech Cyberman
void I_Tactile(int on, int off, int total)
{
}
// Zone memory auto-allocation function that allocates the zone size
// by trying progressively smaller zone sizes until one is found that
// works.
static byte *AutoAllocMemory(int *size, int default_ram, int min_ram)
{
byte *zonemem;
// Allocate the zone memory. This loop tries progressively smaller
// zone sizes until a size is found that can be allocated.
// If we used the -mb command line parameter, only the parameter
// provided is accepted.
zonemem = NULL;
while (zonemem == NULL)
{
// We need a reasonable minimum amount of RAM to start.
if (default_ram < min_ram)
{
I_Error("Unable to allocate %i MiB of RAM for zone", default_ram);
}
// Try to allocate the zone memory.
*size = default_ram * 1024 * 1024;
zonemem = ES_malloc(*size);
// Failed to allocate? Reduce zone size until we reach a size
// that is acceptable.
if (zonemem == NULL)
{
default_ram -= 1;
}
}
return zonemem;
}
byte *I_ZoneBase (int *size)
{
byte *zonemem;
int min_ram, default_ram;
int p;
//!
// @arg <mb>
//
// Specify the heap size, in MiB (default 16).
//
p = M_CheckParmWithArgs("-mb", 1);
if (p > 0)
{
default_ram = ES_atoi(myargv[p+1]);
min_ram = default_ram;
}
else
{
default_ram = DEFAULT_RAM;
min_ram = MIN_RAM;
}
zonemem = AutoAllocMemory(size, default_ram, min_ram);
ES_debugf("zone memory: %p, %x allocated for zone\n",
zonemem, *size);
return zonemem;
}
void I_PrintBanner(char *msg)
{
ES_infof("%s\n", msg);
}
void I_PrintDivider(void)
{
ES_infof("===========================================================================\n");
}
void I_PrintStartupBanner(char *gamedescription)
{
I_PrintDivider();
I_PrintBanner(gamedescription);
I_PrintDivider();
ES_infof(
PACKAGE_NAME " is free software, covered by the GNU General Public"
" License. There is NO warranty; not even for MERCHANTABILITY or FITNESS"
" FOR A PARTICULAR PURPOSE. You are welcome to change and distribute"
" copies under certain conditions. See the source for more information.\n");
I_PrintDivider();
}
//
// I_ConsoleStdout
//
// Returns true if stdout is a real console, false if it is a file
//
boolean I_ConsoleStdout(void)
{
return 0;
}
//
// I_Quit
//
void I_Quit (void)
{
atexit_listentry_t *entry;
// Run through all exit functions
entry = exit_funcs;
while (entry != NULL)
{
entry->func();
entry = entry->next;
}
}
//
// I_Error
//
static boolean already_quitting = false;
void I_Error (char *error, ...)
{
char msgbuf[512];
va_list argptr;
atexit_listentry_t *entry;
boolean exit_gui_popup;
if (already_quitting)
{
ES_warnf("Recursive call to I_Error detected.\n");
}
else
{
already_quitting = true;
}
// Write a copy of the message into buffer.
va_start(argptr, error);
ES_memset(msgbuf, 0, sizeof(msgbuf));
M_vsnprintf(msgbuf, sizeof(msgbuf), error, argptr);
va_end(argptr);
// Shutdown. Here might be other errors.
entry = exit_funcs;
while (entry != NULL)
{
if (entry->run_on_error)
{
entry->func();
}
entry = entry->next;
}
ES_Crash(msgbuf);
}
//
// Read Access Violation emulation.
//
// From PrBoom+, by entryway.
//
// C:\>debug
// -d 0:0
//
// DOS 6.22:
// 0000:0000 (57 92 19 00) F4 06 70 00-(16 00)
// DOS 7.1:
// 0000:0000 (9E 0F C9 00) 65 04 70 00-(16 00)
// Win98:
// 0000:0000 (9E 0F C9 00) 65 04 70 00-(16 00)
// DOSBox under XP:
// 0000:0000 (00 00 00 F1) ?? ?? ?? 00-(07 00)
#define DOS_MEM_DUMP_SIZE 10
static const unsigned char mem_dump_dos622[DOS_MEM_DUMP_SIZE] = {
0x57, 0x92, 0x19, 0x00, 0xF4, 0x06, 0x70, 0x00, 0x16, 0x00};
static const unsigned char mem_dump_win98[DOS_MEM_DUMP_SIZE] = {
0x9E, 0x0F, 0xC9, 0x00, 0x65, 0x04, 0x70, 0x00, 0x16, 0x00};
static const unsigned char mem_dump_dosbox[DOS_MEM_DUMP_SIZE] = {
0x00, 0x00, 0x00, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00};
static unsigned char mem_dump_custom[DOS_MEM_DUMP_SIZE];
static const unsigned char *dos_mem_dump = mem_dump_dos622;
boolean I_GetMemoryValue(unsigned int offset, void *value, int size)
{
static boolean firsttime = true;
if (firsttime)
{
int p, i, val;
firsttime = false;
i = 0;
//!
// @category compat
// @arg <version>
//
// Specify DOS version to emulate for NULL pointer dereference
// emulation. Supported versions are: dos622, dos71, dosbox.
// The default is to emulate DOS 7.1 (Windows 98).
//
p = M_CheckParmWithArgs("-setmem", 1);
if (p > 0)
{
if (!ES_strcasecmp(myargv[p + 1], "dos622"))
{
dos_mem_dump = mem_dump_dos622;
}
if (!ES_strcasecmp(myargv[p + 1], "dos71"))
{
dos_mem_dump = mem_dump_win98;
}
else if (!ES_strcasecmp(myargv[p + 1], "dosbox"))
{
dos_mem_dump = mem_dump_dosbox;
}
else
{
for (i = 0; i < DOS_MEM_DUMP_SIZE; ++i)
{
++p;
if (p >= myargc || myargv[p][0] == '-')
{
break;
}
M_StrToInt(myargv[p], &val);
mem_dump_custom[i++] = (unsigned char) val;
}
dos_mem_dump = mem_dump_custom;
}
}
}
switch (size)
{
case 1:
*((unsigned char *) value) = dos_mem_dump[offset];
return true;
case 2:
*((unsigned short *) value) = dos_mem_dump[offset]
| (dos_mem_dump[offset + 1] << 8);
return true;
case 4:
*((unsigned int *) value) = dos_mem_dump[offset]
| (dos_mem_dump[offset + 1] << 8)
| (dos_mem_dump[offset + 2] << 16)
| (dos_mem_dump[offset + 3] << 24);
return true;
}
return false;
}

85
apps/doom/i_system.h Normal file
View File

@ -0,0 +1,85 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// System specific interface stuff.
//
#ifndef __I_SYSTEM__
#define __I_SYSTEM__
#include "d_ticcmd.h"
#include "d_event.h"
typedef void (*atexit_func_t)(void);
// Called by DoomMain.
void I_Init (void);
// Called by startup code
// to get the ammount of memory to malloc
// for the zone management.
byte* I_ZoneBase (int *size);
boolean I_ConsoleStdout(void);
// Asynchronous interrupt functions should maintain private queues
// that are read by the synchronous functions
// to be converted into events.
// Either returns a null ticcmd,
// or calls a loadable driver to build it.
// This ticcmd will then be modified by the gameloop
// for normal input.
ticcmd_t* I_BaseTiccmd (void);
// Called by M_Responder when quit is selected.
// Clean exit, displays sell blurb.
void I_Quit (void);
__attribute__((noreturn))
void I_Error (char *error, ...);
void I_Tactile (int on, int off, int total);
boolean I_GetMemoryValue(unsigned int offset, void *value, int size);
// Schedule a function to be called when the program exits.
// If run_if_error is true, the function is called if the exit
// is due to an error (I_Error)
void I_AtExit(atexit_func_t func, boolean run_if_error);
// Add all system-specific config file variable bindings.
void I_BindVariables(void);
// Print startup banner copyright message.
void I_PrintStartupBanner(char *gamedescription);
// Print a centered text banner displaying the given string.
void I_PrintBanner(char *text);
// Print a dividing line for startup banners.
void I_PrintDivider(void);
#endif

76
apps/doom/i_timer.c Normal file
View File

@ -0,0 +1,76 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Timer functions.
//
#include "essence/include.h"
#include "i_timer.h"
#include "doomtype.h"
//
// I_GetTime
// returns time in 1/35th second tics
//
static uint32_t basetime = 0;
int I_GetTicks(void)
{
return ES_GetTicksMs();
}
int I_GetTime (void)
{
uint32_t ticks;
ticks = I_GetTicks();
if (basetime == 0)
basetime = ticks;
ticks -= basetime;
return (ticks * TICRATE) / 1000;
}
//
// Same as I_GetTime, but returns time in milliseconds
//
int I_GetTimeMS(void)
{
uint32_t ticks;
ticks = I_GetTicks();
if (basetime == 0)
basetime = ticks;
return ticks - basetime;
}
// Sleep for a specified number of ms
void I_Sleep(int ms)
{
ES_SleepMs(ms);
}
void I_WaitVBL(int count)
{}
void I_InitTimer(void)
{}

42
apps/doom/i_timer.h Normal file
View File

@ -0,0 +1,42 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// System-specific timer interface
//
#ifndef __I_TIMER__
#define __I_TIMER__
#define TICRATE 35
// Called by D_DoomLoop,
// returns current time in tics.
int I_GetTime (void);
// returns current time in ms
int I_GetTimeMS (void);
// Pause for a specified number of ms
void I_Sleep(int ms);
// Initialize timer
void I_InitTimer(void);
// Wait for vertical retrace or pause a bit.
void I_WaitVBL(int count);
#endif

397
apps/doom/i_video.c Normal file
View File

@ -0,0 +1,397 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id:$
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// $Log:$
//
// DESCRIPTION:
// DOOM graphics stuff for X11, UNIX.
//
//-----------------------------------------------------------------------------
#include "essence/include.h"
#include "config.h"
#include "v_video.h"
#include "m_argv.h"
#include "d_event.h"
#include "d_main.h"
#include "i_video.h"
#include "z_zone.h"
#include "tables.h"
#include "doomkeys.h"
struct FB_BitField
{
uint32_t offset; /* beginning of bitfield */
uint32_t length; /* length of bitfield */
};
struct FB_ScreenInfo
{
uint32_t xres; /* visible resolution */
uint32_t yres;
uint32_t xres_virtual; /* virtual resolution */
uint32_t yres_virtual;
uint32_t bits_per_pixel; /* guess what */
/* >1 = FOURCC */
struct FB_BitField red; /* bitfield in s_Fb mem if true color, */
struct FB_BitField green; /* else only length is significant */
struct FB_BitField blue;
struct FB_BitField transp; /* transparency */
};
static struct FB_ScreenInfo s_Fb;
uint32_t fb_scaling = 1;
int usemouse = 0;
#ifdef CMAP256
boolean palette_changed;
struct color colors[256];
#else // CMAP256
static struct color colors[256];
#endif // CMAP256
void I_GetEvent(void);
// The screen buffer; this is modified to draw things to the screen
byte *I_VideoBuffer = NULL;
// If true, game is running as a screensaver
boolean screensaver_mode = false;
// Flag indicating whether the screen is currently visible:
// when the screen isnt visible, don't render the screen
boolean screenvisible;
// Mouse acceleration
//
// This emulates some of the behavior of DOS mouse drivers by increasing
// the speed when the mouse is moved fast.
//
// The mouse input values are input directly to the game, but when
// the values exceed the value of mouse_threshold, they are multiplied
// by mouse_acceleration to increase the speed.
float mouse_acceleration = 2.0;
int mouse_threshold = 10;
// Gamma correction level to use
int usegamma = 0;
typedef struct
{
byte r;
byte g;
byte b;
} col_t;
// Palette converted to RGB565
static uint16_t rgb565_palette[256];
void cmap_to_rgb565(uint16_t * out, uint8_t * in, size_t in_pixels)
{
size_t i, j;
struct color c;
uint16_t r, g, b;
for (i = 0; i < in_pixels; i++)
{
c = colors[*in];
r = ((uint16_t)(c.r >> 3)) << 11;
g = ((uint16_t)(c.g >> 2)) << 5;
b = ((uint16_t)(c.b >> 3)) << 0;
*out = (r | g | b);
in++;
for (j = 0; j < fb_scaling; j++) {
out++;
}
}
}
void cmap_to_fb(uint8_t * out, uint8_t * in, size_t in_pixels)
{
size_t i, j, k;
struct color c;
uint32_t pix;
uint16_t r, g, b;
for (i = 0; i < in_pixels; i++)
{
c = colors[*in]; /* R:8 G:8 B:8 format! */
r = (uint16_t)(c.r >> (8 - s_Fb.red.length));
g = (uint16_t)(c.g >> (8 - s_Fb.green.length));
b = (uint16_t)(c.b >> (8 - s_Fb.blue.length));
pix = r << s_Fb.red.offset;
pix |= g << s_Fb.green.offset;
pix |= b << s_Fb.blue.offset;
for (k = 0; k < fb_scaling; k++) {
for (j = 0; j < s_Fb.bits_per_pixel/8; j++) {
*out = (pix >> (j*8));
out++;
}
}
in++;
}
}
void I_InitGraphics (void)
{
ES_memset(&s_Fb, 0, sizeof(struct FB_ScreenInfo));
s_Fb.xres = RES_X;
s_Fb.yres = RES_Y;
s_Fb.xres_virtual = s_Fb.xres;
s_Fb.yres_virtual = s_Fb.yres;
#ifdef CMAP256
s_Fb.bits_per_pixel = 8;
#else // CMAP256
s_Fb.bits_per_pixel = 32;
s_Fb.blue.length = 8;
s_Fb.green.length = 8;
s_Fb.red.length = 8;
s_Fb.transp.length = 8;
s_Fb.blue.offset = 0;
s_Fb.green.offset = 8;
s_Fb.red.offset = 16;
s_Fb.transp.offset = 24;
#endif // CMAP256
ES_debugf("I_InitGraphics: framebuffer: x_res: %d, y_res: %d, x_virtual: %d, y_virtual: %d, bpp: %d\n",
s_Fb.xres, s_Fb.yres, s_Fb.xres_virtual, s_Fb.yres_virtual, s_Fb.bits_per_pixel);
ES_debugf("I_InitGraphics: framebuffer: RGBA: %d%d%d%d, red_off: %d, green_off: %d, blue_off: %d, transp_off: %d\n",
s_Fb.red.length, s_Fb.green.length, s_Fb.blue.length, s_Fb.transp.length, s_Fb.red.offset, s_Fb.green.offset, s_Fb.blue.offset, s_Fb.transp.offset);
ES_debugf("I_InitGraphics: DOOM screen size: w x h: %d x %d\n", SCREENWIDTH, SCREENHEIGHT);
int i = M_CheckParmWithArgs("-scaling", 1);
if (i > 0) {
fb_scaling = (uint32_t)ES_atoi(myargv[i + 1]);
ES_debugf("I_InitGraphics: Scaling factor: %d\n", fb_scaling);
} else {
fb_scaling = s_Fb.xres / SCREENWIDTH;
if (s_Fb.yres / SCREENHEIGHT < fb_scaling)
fb_scaling = s_Fb.yres / SCREENHEIGHT;
ES_debugf("I_InitGraphics: Auto-scaling factor: %d\n", fb_scaling);
}
/* Allocate screen to draw to */
I_VideoBuffer = (byte*)Z_Malloc (SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL); // For DOOM to draw on
screenvisible = true;
extern void I_InitInput(void);
I_InitInput();
}
void I_ShutdownGraphics (void)
{
Z_Free (I_VideoBuffer);
}
void I_StartFrame (void)
{}
void I_StartTic (void)
{
I_GetEvent();
}
void I_UpdateNoBlit (void)
{}
//
// I_FinishUpdate
//
void I_FinishUpdate (void)
{
int y;
int x_offset, y_offset, x_offset_end;
unsigned char *line_in, *line_out;
/* Offsets in case FB is bigger than DOOM */
/* 600 = s_Fb heigt, 200 screenheight */
/* 600 = s_Fb heigt, 200 screenheight */
/* 2048 =s_Fb width, 320 screenwidth */
y_offset = (((s_Fb.yres - (SCREENHEIGHT * fb_scaling)) * s_Fb.bits_per_pixel/8)) / 2;
x_offset = (((s_Fb.xres - (SCREENWIDTH * fb_scaling)) * s_Fb.bits_per_pixel/8)) / 2; // XXX: siglent FB hack: /4 instead of /2, since it seems to handle the resolution in a funny way
//x_offset = 0;
x_offset_end = ((s_Fb.xres - (SCREENWIDTH * fb_scaling)) * s_Fb.bits_per_pixel/8) - x_offset;
/* DRAW SCREEN */
line_in = (unsigned char *) I_VideoBuffer;
line_out = (unsigned char *) ES_ScreenBuffer;
y = SCREENHEIGHT;
while (y--)
{
size_t i;
for (i = 0; i < fb_scaling; i++) {
line_out += x_offset;
#ifdef CMAP256
if (fb_scaling == 1) {
ES_memcpy(line_out, line_in, SCREENWIDTH); /* fb_width is bigger than Doom SCREENWIDTH... */
} else {
int j;
for (j = 0; j < SCREENWIDTH; j++) {
int k;
for (k = 0; k < fb_scaling; k++) {
line_out[j * fb_scaling + k] = line_in[j];
}
}
}
#else
//cmap_to_rgb565((void*)line_out, (void*)line_in, SCREENWIDTH);
cmap_to_fb((void*)line_out, (void*)line_in, SCREENWIDTH);
#endif
line_out += (SCREENWIDTH * fb_scaling * (s_Fb.bits_per_pixel/8)) + x_offset_end;
}
line_in += SCREENWIDTH;
}
}
//
// I_ReadScreen
//
void I_ReadScreen (byte* scr)
{
ES_memcpy (scr, I_VideoBuffer, SCREENWIDTH * SCREENHEIGHT);
}
//
// I_SetPalette
//
#define GFX_RGB565(r, g, b) ((((r & 0xF8) >> 3) << 11) | (((g & 0xFC) >> 2) << 5) | ((b & 0xF8) >> 3))
#define GFX_RGB565_R(color) ((0xF800 & color) >> 11)
#define GFX_RGB565_G(color) ((0x07E0 & color) >> 5)
#define GFX_RGB565_B(color) (0x001F & color)
void I_SetPalette (byte* palette)
{
int i;
/* performance boost:
* map to the right pixel format over here! */
for (i=0; i<256; ++i ) {
colors[i].a = 0;
colors[i].r = gammatable[usegamma][*palette++];
colors[i].g = gammatable[usegamma][*palette++];
colors[i].b = gammatable[usegamma][*palette++];
}
#ifdef CMAP256
palette_changed = true;
#endif // CMAP256
}
// Given an RGB value, find the closest matching palette index.
int I_GetPaletteIndex(int r, int g, int b)
{
int best, best_diff, diff;
int i;
col_t color;
ES_debugf("I_GetPaletteIndex\n");
best = 0;
best_diff = INT_MAX;
for (i = 0; i < 256; ++i)
{
color.r = GFX_RGB565_R(rgb565_palette[i]);
color.g = GFX_RGB565_G(rgb565_palette[i]);
color.b = GFX_RGB565_B(rgb565_palette[i]);
diff = (r - color.r) * (r - color.r)
+ (g - color.g) * (g - color.g)
+ (b - color.b) * (b - color.b);
if (diff < best_diff)
{
best = i;
best_diff = diff;
}
if (diff == 0)
{
break;
}
}
return best;
}
void I_BeginRead(void)
{}
void I_EndRead(void)
{}
void I_SetWindowTitle(char *title)
{
ES_debugf("I_SetWindowTitle: %s\n", title);
}
void I_GraphicsCheckCommandLine(void)
{}
void I_SetGrabMouseCallback(grabmouse_callback_t func)
{}
void I_EnableLoadingDisk(void)
{}
void I_BindVideoVariables(void)
{}
void I_DisplayFPSDots(boolean dots_on)
{}
void I_CheckIsScreensaver(void)
{}

175
apps/doom/i_video.h Normal file
View File

@ -0,0 +1,175 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// System specific interface stuff.
//
#ifndef __I_VIDEO__
#define __I_VIDEO__
#include "doomtype.h"
// Screen width and height.
#define SCREENWIDTH 320
#define SCREENHEIGHT 200
// Screen width used for "squash" scale functions
#define SCREENWIDTH_4_3 256
// Screen height used for "stretch" scale functions.
#define SCREENHEIGHT_4_3 240
#define MAX_MOUSE_BUTTONS 8
typedef struct
{
// Screen width and height
int width;
int height;
// Initialisation function to call when using this mode.
// Called with a pointer to the Doom palette.
//
// If NULL, no init function is called.
void (*InitMode)(byte *palette);
// Function to call to draw the screen from the source buffer.
// Return true if draw was successful.
boolean (*DrawScreen)(int x1, int y1, int x2, int y2);
// If true, this is a "poor quality" mode. The autoadjust
// code should always attempt to use a different mode to this
// mode in fullscreen.
//
// Some notes about what "poor quality" means in this context:
//
// The aspect ratio correction works by scaling up to the larger
// screen size and then drawing pixels on the edges between the
// "virtual" pixels so that an authentic blocky look-and-feel is
// achieved.
//
// For a mode like 640x480, you can imagine the grid of the
// "original" pixels spaced out, with extra "blurry" pixels added
// in the space between them to fill it out. However, when you're
// running at a resolution like 320x240, this is not the case. In
// the small screen case, every single pixel has to be a blurry
// interpolation of two pixels from the original image.
//
// If you run in 320x240 and put your face up close to the screen
// you can see this: it's particularly visible in the small yellow
// status bar numbers for example. Overall it still looks "okay"
// but there's an obvious - albeit small - deterioration in
// quality.
//
// Once you get to 640x480, all the original pixels are there at
// least once and it's okay (the higher the resolution, the more
// accurate it is). When I first wrote the code I was expecting
// that even higher resolutions would be needed before it would
// look acceptable, but it turned out to be okay even at 640x480.
boolean poor_quality;
} screen_mode_t;
typedef boolean (*grabmouse_callback_t)(void);
// Called by D_DoomMain,
// determines the hardware configuration
// and sets up the video mode
void I_InitGraphics (void);
void I_GraphicsCheckCommandLine(void);
void I_ShutdownGraphics(void);
// Takes full 8 bit values.
void I_SetPalette (byte* palette);
int I_GetPaletteIndex(int r, int g, int b);
void I_UpdateNoBlit (void);
void I_FinishUpdate (void);
void I_ReadScreen (byte* scr);
void I_BeginRead (void);
void I_SetWindowTitle(char *title);
void I_CheckIsScreensaver(void);
void I_SetGrabMouseCallback(grabmouse_callback_t func);
void I_DisplayFPSDots(boolean dots_on);
void I_BindVideoVariables(void);
void I_InitWindowTitle(void);
void I_InitWindowIcon(void);
// Called before processing any tics in a frame (just after displaying a frame).
// Time consuming syncronous operations are performed here (joystick reading).
void I_StartFrame (void);
// Called before processing each tic in a frame.
// Quick syncronous operations are performed here.
void I_StartTic (void);
// Enable the loading disk image displayed when reading from disk.
void I_EnableLoadingDisk(void);
void I_EndRead (void);
struct color {
uint32_t b:8;
uint32_t g:8;
uint32_t r:8;
uint32_t a:8;
};
extern char *video_driver;
extern boolean screenvisible;
extern float mouse_acceleration;
extern int mouse_threshold;
extern int vanilla_keyboard_mapping;
extern boolean screensaver_mode;
extern int usegamma;
extern byte *I_VideoBuffer;
extern int screen_width;
extern int screen_height;
extern int screen_bpp;
extern int fullscreen;
extern int aspect_ratio_correct;
extern int show_diskicon;
extern int diskicon_readbytes;
#ifdef CMAP256
extern boolean palette_changed;
extern struct color colors[256];
#endif // CMAP256
#endif

4661
apps/doom/info.c Normal file

File diff suppressed because it is too large Load Diff

1331
apps/doom/info.h Normal file

File diff suppressed because it is too large Load Diff

82
apps/doom/m_argv.c Normal file
View File

@ -0,0 +1,82 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
//
#include "essence/include.h"
#include "doomtype.h"
#include "i_system.h"
#include "m_misc.h"
#include "m_argv.h" // haleyjd 20110212: warning fix
int myargc;
char** myargv;
//
// M_CheckParm
// Checks for the given parameter
// in the program's command line arguments.
// Returns the argument number (1 to argc-1)
// or 0 if not present
//
int M_CheckParmWithArgs(char *check, int num_args)
{
for (int i = 1; i < myargc - num_args; i++)
{
if (!ES_strcasecmp(check, myargv[i]))
return i;
}
return 0;
}
//
// M_ParmExists
//
// Returns true if the given parameter exists in the program's command
// line arguments, false if not.
//
boolean M_ParmExists(char *check)
{
return M_CheckParm(check) != 0;
}
int M_CheckParm(char *check)
{
return M_CheckParmWithArgs(check, 0);
}
#define MAXARGVS 100
// Return the name of the executable used to start the program:
char *M_GetExecutableName(void)
{
char *sep;
sep = ES_strchr(myargv[0], DIR_SEPARATOR);
if (sep == NULL)
{
return myargv[0];
}
else
{
return sep + 1;
}
}

49
apps/doom/m_argv.h Normal file
View File

@ -0,0 +1,49 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Nil.
//
#ifndef __M_ARGV__
#define __M_ARGV__
#include "doomtype.h"
//
// MISC
//
extern int myargc;
extern char** myargv;
// Returns the position of the given parameter
// in the arg list (0 if not found).
int M_CheckParm (char* check);
// Same as M_CheckParm, but checks that num_args arguments are available
// following the specified argument.
int M_CheckParmWithArgs(char *check, int num_args);
void M_FindResponseFile(void);
// Parameter has been specified?
boolean M_ParmExists(char *check);
// Get name of executable used to run this program:
char *M_GetExecutableName(void);
#endif

54
apps/doom/m_bbox.c Normal file
View File

@ -0,0 +1,54 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Main loop menu stuff.
// Random number LUT.
// Default Config File.
// PCX Screenshots.
//
#include "m_bbox.h"
void M_ClearBox (fixed_t *box)
{
box[BOXTOP] = box[BOXRIGHT] = INT_MIN;
box[BOXBOTTOM] = box[BOXLEFT] = INT_MAX;
}
void
M_AddToBox
( fixed_t* box,
fixed_t x,
fixed_t y )
{
if (x<box[BOXLEFT])
box[BOXLEFT] = x;
else if (x>box[BOXRIGHT])
box[BOXRIGHT] = x;
if (y<box[BOXBOTTOM])
box[BOXBOTTOM] = y;
else if (y>box[BOXTOP])
box[BOXTOP] = y;
}

45
apps/doom/m_bbox.h Normal file
View File

@ -0,0 +1,45 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Nil.
//
#ifndef __M_BBOX__
#define __M_BBOX__
#include "essence/include.h"
#include "m_fixed.h"
// Bounding box coordinate storage.
enum
{
BOXTOP,
BOXBOTTOM,
BOXLEFT,
BOXRIGHT
}; // bbox coordinates
// Bounding box functions.
void M_ClearBox (fixed_t* box);
void
M_AddToBox
( fixed_t* box,
fixed_t x,
fixed_t y );
#endif

87
apps/doom/m_cheat.c Normal file
View File

@ -0,0 +1,87 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Cheat sequence checking.
//
#include "essence/include.h"
#include "doomtype.h"
#include "m_cheat.h"
//
// CHEAT SEQUENCE PACKAGE
//
//
// Called in st_stuff module, which handles the input.
// Returns a 1 if the cheat was successful, 0 if failed.
//
int
cht_CheckCheat
( cheatseq_t* cht,
char key )
{
// if we make a short sequence on a cheat with parameters, this
// will not work in vanilla doom. behave the same.
if (cht->parameter_chars > 0 && ES_strlen(cht->sequence) < cht->sequence_len)
return false;
if (cht->chars_read < ES_strlen(cht->sequence))
{
// still reading characters from the cheat code
// and verifying. reset back to the beginning
// if a key is wrong
if (key == cht->sequence[cht->chars_read])
++cht->chars_read;
else
cht->chars_read = 0;
cht->param_chars_read = 0;
}
else if (cht->param_chars_read < cht->parameter_chars)
{
// we have passed the end of the cheat sequence and are
// entering parameters now
cht->parameter_buf[cht->param_chars_read] = key;
++cht->param_chars_read;
}
if (cht->chars_read >= ES_strlen(cht->sequence)
&& cht->param_chars_read >= cht->parameter_chars)
{
cht->chars_read = cht->param_chars_read = 0;
return true;
}
// cheat not matched yet
return false;
}
void
cht_GetParam
( cheatseq_t* cht,
char* buffer )
{
ES_memcpy(buffer, cht->parameter_buf, cht->parameter_chars);
}

62
apps/doom/m_cheat.h Normal file
View File

@ -0,0 +1,62 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Cheat code checking.
//
#ifndef __M_CHEAT__
#define __M_CHEAT__
//
// CHEAT SEQUENCE PACKAGE
//
// declaring a cheat
#define CHEAT(value, parameters) \
{ value, sizeof(value) - 1, parameters, 0, 0, "" }
#define MAX_CHEAT_LEN 25
#define MAX_CHEAT_PARAMS 5
typedef struct
{
// settings for this cheat
char sequence[MAX_CHEAT_LEN];
size_t sequence_len;
int parameter_chars;
// state used during the game
size_t chars_read;
int param_chars_read;
char parameter_buf[MAX_CHEAT_PARAMS];
} cheatseq_t;
int
cht_CheckCheat
( cheatseq_t* cht,
char key );
void
cht_GetParam
( cheatseq_t* cht,
char* buffer );
#endif

1937
apps/doom/m_config.c Normal file

File diff suppressed because it is too large Load Diff

39
apps/doom/m_config.h Normal file
View File

@ -0,0 +1,39 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Configuration file interface.
//
#ifndef __M_CONFIG__
#define __M_CONFIG__
#include "doomtype.h"
void M_LoadDefaults(void);
void M_SaveDefaults(void);
void M_SaveDefaultsAlternate(char *main, char *extra);
void M_SetConfigDir(char *dir);
void M_BindVariable(char *name, void *variable);
boolean M_SetVariable(char *name, char *value);
int M_GetIntVariable(char *name);
const char *M_GetStrVariable(char *name);
float M_GetFloatVariable(char *name);
void M_SetConfigFilenames(char *main_config, char *extra_config);
char *M_GetSaveGameDir(char *iwadname);
extern char *configdir;
#endif

398
apps/doom/m_controls.c Normal file
View File

@ -0,0 +1,398 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 1993-2008 Raven Software
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include "essence/include.h"
#include "doomtype.h"
#include "doomkeys.h"
#include "m_config.h"
#include "m_misc.h"
//
// Keyboard controls
//
int key_right = KEY_RIGHTARROW;
int key_left = KEY_LEFTARROW;
int key_up = KEY_UPARROW;
int key_down = KEY_DOWNARROW;
int key_strafeleft = KEY_STRAFE_L;
int key_straferight = KEY_STRAFE_R;
int key_fire = KEY_FIRE;
int key_use = KEY_USE;
int key_strafe = KEY_RALT;
int key_speed = KEY_RSHIFT;
//
// Heretic keyboard controls
//
int key_flyup = KEY_PGUP;
int key_flydown = KEY_INS;
int key_flycenter = KEY_HOME;
int key_lookup = KEY_PGDN;
int key_lookdown = KEY_DEL;
int key_lookcenter = KEY_END;
int key_invleft = '[';
int key_invright = ']';
int key_useartifact = KEY_ENTER;
//
// Hexen key controls
//
int key_jump = '/';
int key_arti_all = KEY_BACKSPACE;
int key_arti_health = '\\';
int key_arti_poisonbag = '0';
int key_arti_blastradius = '9';
int key_arti_teleport = '8';
int key_arti_teleportother = '7';
int key_arti_egg = '6';
int key_arti_invulnerability = '5';
//
// Strife key controls
//
// haleyjd 09/01/10
//
// Note: Strife also uses key_invleft, key_invright, key_jump, key_lookup, and
// key_lookdown, but with different default values.
int key_usehealth = 'h';
int key_invquery = 'q';
int key_mission = 'w';
int key_invpop = 'z';
int key_invkey = 'k';
int key_invhome = KEY_HOME;
int key_invend = KEY_END;
int key_invuse = KEY_ENTER;
int key_invdrop = KEY_BACKSPACE;
//
// Mouse controls
//
int mousebfire = 0;
int mousebstrafe = 1;
int mousebforward = 2;
int mousebjump = -1;
int mousebstrafeleft = -1;
int mousebstraferight = -1;
int mousebbackward = -1;
int mousebuse = -1;
int mousebprevweapon = -1;
int mousebnextweapon = -1;
int key_message_refresh = KEY_ENTER;
int key_pause = KEY_PAUSE;
int key_demo_quit = 'q';
int key_spy = KEY_F12;
// Multiplayer chat keys:
int key_multi_msg = 't';
int key_multi_msgplayer[8];
// Weapon selection keys:
int key_weapon1 = '1';
int key_weapon2 = '2';
int key_weapon3 = '3';
int key_weapon4 = '4';
int key_weapon5 = '5';
int key_weapon6 = '6';
int key_weapon7 = '7';
int key_weapon8 = '8';
int key_prevweapon = 0;
int key_nextweapon = 0;
// Map control keys:
int key_map_north = KEY_UPARROW;
int key_map_south = KEY_DOWNARROW;
int key_map_east = KEY_RIGHTARROW;
int key_map_west = KEY_LEFTARROW;
int key_map_zoomin = '=';
int key_map_zoomout = '-';
int key_map_toggle = KEY_TAB;
int key_map_maxzoom = '0';
int key_map_follow = 'f';
int key_map_grid = 'g';
int key_map_mark = 'm';
int key_map_clearmark = 'c';
// menu keys:
int key_menu_activate = KEY_ESCAPE;
int key_menu_up = KEY_UPARROW;
int key_menu_down = KEY_DOWNARROW;
int key_menu_left = KEY_LEFTARROW;
int key_menu_right = KEY_RIGHTARROW;
int key_menu_back = KEY_BACKSPACE;
int key_menu_forward = KEY_ENTER;
int key_menu_confirm = 'y';
int key_menu_abort = 'n';
int key_menu_help = KEY_F1;
int key_menu_save = KEY_F2;
int key_menu_load = KEY_F3;
int key_menu_volume = KEY_F4;
int key_menu_detail = KEY_F5;
int key_menu_qsave = KEY_F6;
int key_menu_endgame = KEY_F7;
int key_menu_messages = KEY_F8;
int key_menu_qload = KEY_F9;
int key_menu_quit = KEY_F10;
int key_menu_gamma = KEY_F11;
int key_menu_incscreen = KEY_EQUALS;
int key_menu_decscreen = KEY_MINUS;
int key_menu_screenshot = 0;
//
// Joystick controls
//
int joybfire = 0;
int joybstrafe = 1;
int joybuse = 3;
int joybspeed = 2;
int joybstrafeleft = -1;
int joybstraferight = -1;
int joybjump = -1;
int joybprevweapon = -1;
int joybnextweapon = -1;
int joybmenu = -1;
// Control whether if a mouse button is double clicked, it acts like
// "use" has been pressed
int dclick_use = 1;
//
// Bind all of the common controls used by Doom and all other games.
//
void M_BindBaseControls(void)
{
M_BindVariable("key_right", &key_right);
M_BindVariable("key_left", &key_left);
M_BindVariable("key_up", &key_up);
M_BindVariable("key_down", &key_down);
M_BindVariable("key_strafeleft", &key_strafeleft);
M_BindVariable("key_straferight", &key_straferight);
M_BindVariable("key_fire", &key_fire);
M_BindVariable("key_use", &key_use);
M_BindVariable("key_strafe", &key_strafe);
M_BindVariable("key_speed", &key_speed);
M_BindVariable("mouseb_fire", &mousebfire);
M_BindVariable("mouseb_strafe", &mousebstrafe);
M_BindVariable("mouseb_forward", &mousebforward);
M_BindVariable("joyb_fire", &joybfire);
M_BindVariable("joyb_strafe", &joybstrafe);
M_BindVariable("joyb_use", &joybuse);
M_BindVariable("joyb_speed", &joybspeed);
M_BindVariable("joyb_menu_activate", &joybmenu);
// Extra controls that are not in the Vanilla versions:
M_BindVariable("joyb_strafeleft", &joybstrafeleft);
M_BindVariable("joyb_straferight", &joybstraferight);
M_BindVariable("mouseb_strafeleft", &mousebstrafeleft);
M_BindVariable("mouseb_straferight", &mousebstraferight);
M_BindVariable("mouseb_use", &mousebuse);
M_BindVariable("mouseb_backward", &mousebbackward);
M_BindVariable("dclick_use", &dclick_use);
M_BindVariable("key_pause", &key_pause);
M_BindVariable("key_message_refresh", &key_message_refresh);
}
void M_BindHereticControls(void)
{
M_BindVariable("key_flyup", &key_flyup);
M_BindVariable("key_flydown", &key_flydown);
M_BindVariable("key_flycenter", &key_flycenter);
M_BindVariable("key_lookup", &key_lookup);
M_BindVariable("key_lookdown", &key_lookdown);
M_BindVariable("key_lookcenter", &key_lookcenter);
M_BindVariable("key_invleft", &key_invleft);
M_BindVariable("key_invright", &key_invright);
M_BindVariable("key_useartifact", &key_useartifact);
}
void M_BindHexenControls(void)
{
M_BindVariable("key_jump", &key_jump);
M_BindVariable("mouseb_jump", &mousebjump);
M_BindVariable("joyb_jump", &joybjump);
M_BindVariable("key_arti_all", &key_arti_all);
M_BindVariable("key_arti_health", &key_arti_health);
M_BindVariable("key_arti_poisonbag", &key_arti_poisonbag);
M_BindVariable("key_arti_blastradius", &key_arti_blastradius);
M_BindVariable("key_arti_teleport", &key_arti_teleport);
M_BindVariable("key_arti_teleportother", &key_arti_teleportother);
M_BindVariable("key_arti_egg", &key_arti_egg);
M_BindVariable("key_arti_invulnerability", &key_arti_invulnerability);
}
void M_BindStrifeControls(void)
{
// These are shared with all games, but have different defaults:
key_message_refresh = '/';
// These keys are shared with Heretic/Hexen but have different defaults:
key_jump = 'a';
key_lookup = KEY_PGUP;
key_lookdown = KEY_PGDN;
key_invleft = KEY_INS;
key_invright = KEY_DEL;
M_BindVariable("key_jump", &key_jump);
M_BindVariable("key_lookUp", &key_lookup);
M_BindVariable("key_lookDown", &key_lookdown);
M_BindVariable("key_invLeft", &key_invleft);
M_BindVariable("key_invRight", &key_invright);
// Custom Strife-only Keys:
M_BindVariable("key_useHealth", &key_usehealth);
M_BindVariable("key_invquery", &key_invquery);
M_BindVariable("key_mission", &key_mission);
M_BindVariable("key_invPop", &key_invpop);
M_BindVariable("key_invKey", &key_invkey);
M_BindVariable("key_invHome", &key_invhome);
M_BindVariable("key_invEnd", &key_invend);
M_BindVariable("key_invUse", &key_invuse);
M_BindVariable("key_invDrop", &key_invdrop);
// Strife also supports jump on mouse and joystick, and in the exact same
// manner as Hexen!
M_BindVariable("mouseb_jump", &mousebjump);
M_BindVariable("joyb_jump", &joybjump);
}
void M_BindWeaponControls(void)
{
M_BindVariable("key_weapon1", &key_weapon1);
M_BindVariable("key_weapon2", &key_weapon2);
M_BindVariable("key_weapon3", &key_weapon3);
M_BindVariable("key_weapon4", &key_weapon4);
M_BindVariable("key_weapon5", &key_weapon5);
M_BindVariable("key_weapon6", &key_weapon6);
M_BindVariable("key_weapon7", &key_weapon7);
M_BindVariable("key_weapon8", &key_weapon8);
M_BindVariable("key_prevweapon", &key_prevweapon);
M_BindVariable("key_nextweapon", &key_nextweapon);
M_BindVariable("joyb_prevweapon", &joybprevweapon);
M_BindVariable("joyb_nextweapon", &joybnextweapon);
M_BindVariable("mouseb_prevweapon", &mousebprevweapon);
M_BindVariable("mouseb_nextweapon", &mousebnextweapon);
}
void M_BindMapControls(void)
{
M_BindVariable("key_map_north", &key_map_north);
M_BindVariable("key_map_south", &key_map_south);
M_BindVariable("key_map_east", &key_map_east);
M_BindVariable("key_map_west", &key_map_west);
M_BindVariable("key_map_zoomin", &key_map_zoomin);
M_BindVariable("key_map_zoomout", &key_map_zoomout);
M_BindVariable("key_map_toggle", &key_map_toggle);
M_BindVariable("key_map_maxzoom", &key_map_maxzoom);
M_BindVariable("key_map_follow", &key_map_follow);
M_BindVariable("key_map_grid", &key_map_grid);
M_BindVariable("key_map_mark", &key_map_mark);
M_BindVariable("key_map_clearmark", &key_map_clearmark);
}
void M_BindMenuControls(void)
{
M_BindVariable("key_menu_activate", &key_menu_activate);
M_BindVariable("key_menu_up", &key_menu_up);
M_BindVariable("key_menu_down", &key_menu_down);
M_BindVariable("key_menu_left", &key_menu_left);
M_BindVariable("key_menu_right", &key_menu_right);
M_BindVariable("key_menu_back", &key_menu_back);
M_BindVariable("key_menu_forward", &key_menu_forward);
M_BindVariable("key_menu_confirm", &key_menu_confirm);
M_BindVariable("key_menu_abort", &key_menu_abort);
M_BindVariable("key_menu_help", &key_menu_help);
M_BindVariable("key_menu_save", &key_menu_save);
M_BindVariable("key_menu_load", &key_menu_load);
M_BindVariable("key_menu_volume", &key_menu_volume);
M_BindVariable("key_menu_detail", &key_menu_detail);
M_BindVariable("key_menu_qsave", &key_menu_qsave);
M_BindVariable("key_menu_endgame", &key_menu_endgame);
M_BindVariable("key_menu_messages", &key_menu_messages);
M_BindVariable("key_menu_qload", &key_menu_qload);
M_BindVariable("key_menu_quit", &key_menu_quit);
M_BindVariable("key_menu_gamma", &key_menu_gamma);
M_BindVariable("key_menu_incscreen", &key_menu_incscreen);
M_BindVariable("key_menu_decscreen", &key_menu_decscreen);
M_BindVariable("key_menu_screenshot",&key_menu_screenshot);
M_BindVariable("key_demo_quit", &key_demo_quit);
M_BindVariable("key_spy", &key_spy);
}
void M_BindChatControls(unsigned int num_players)
{
char name[32]; // haleyjd: 20 not large enough - Thank you, come again!
unsigned int i; // haleyjd: signedness conflict
M_BindVariable("key_multi_msg", &key_multi_msg);
for (i=0; i<num_players; ++i)
{
M_snprintf(name, sizeof(name), "key_multi_msgplayer%i", i + 1);
M_BindVariable(name, &key_multi_msgplayer[i]);
}
}
//
// Apply custom patches to the default values depending on the
// platform we are running on.
//
void M_ApplyPlatformDefaults(void)
{
// no-op. Add your platform-specific patches here.
}

168
apps/doom/m_controls.h Normal file
View File

@ -0,0 +1,168 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 1993-2008 Raven Software
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef __M_CONTROLS_H__
#define __M_CONTROLS_H__
extern int key_right;
extern int key_left;
extern int key_up;
extern int key_down;
extern int key_strafeleft;
extern int key_straferight;
extern int key_fire;
extern int key_use;
extern int key_strafe;
extern int key_speed;
extern int key_jump;
extern int key_flyup;
extern int key_flydown;
extern int key_flycenter;
extern int key_lookup;
extern int key_lookdown;
extern int key_lookcenter;
extern int key_invleft;
extern int key_invright;
extern int key_useartifact;
// villsa [STRIFE] strife keys
extern int key_usehealth;
extern int key_invquery;
extern int key_mission;
extern int key_invpop;
extern int key_invkey;
extern int key_invhome;
extern int key_invend;
extern int key_invuse;
extern int key_invdrop;
extern int key_message_refresh;
extern int key_pause;
extern int key_multi_msg;
extern int key_multi_msgplayer[8];
extern int key_weapon1;
extern int key_weapon2;
extern int key_weapon3;
extern int key_weapon4;
extern int key_weapon5;
extern int key_weapon6;
extern int key_weapon7;
extern int key_weapon8;
extern int key_arti_all;
extern int key_arti_health;
extern int key_arti_poisonbag;
extern int key_arti_blastradius;
extern int key_arti_teleport;
extern int key_arti_teleportother;
extern int key_arti_egg;
extern int key_arti_invulnerability;
extern int key_demo_quit;
extern int key_spy;
extern int key_prevweapon;
extern int key_nextweapon;
extern int key_map_north;
extern int key_map_south;
extern int key_map_east;
extern int key_map_west;
extern int key_map_zoomin;
extern int key_map_zoomout;
extern int key_map_toggle;
extern int key_map_maxzoom;
extern int key_map_follow;
extern int key_map_grid;
extern int key_map_mark;
extern int key_map_clearmark;
// menu keys:
extern int key_menu_activate;
extern int key_menu_up;
extern int key_menu_down;
extern int key_menu_left;
extern int key_menu_right;
extern int key_menu_back;
extern int key_menu_forward;
extern int key_menu_confirm;
extern int key_menu_abort;
extern int key_menu_help;
extern int key_menu_save;
extern int key_menu_load;
extern int key_menu_volume;
extern int key_menu_detail;
extern int key_menu_qsave;
extern int key_menu_endgame;
extern int key_menu_messages;
extern int key_menu_qload;
extern int key_menu_quit;
extern int key_menu_gamma;
extern int key_menu_incscreen;
extern int key_menu_decscreen;
extern int key_menu_screenshot;
extern int mousebfire;
extern int mousebstrafe;
extern int mousebforward;
extern int mousebjump;
extern int mousebstrafeleft;
extern int mousebstraferight;
extern int mousebbackward;
extern int mousebuse;
extern int mousebprevweapon;
extern int mousebnextweapon;
extern int joybfire;
extern int joybstrafe;
extern int joybuse;
extern int joybspeed;
extern int joybjump;
extern int joybstrafeleft;
extern int joybstraferight;
extern int joybprevweapon;
extern int joybnextweapon;
extern int joybmenu;
extern int dclick_use;
void M_BindBaseControls(void);
void M_BindHereticControls(void);
void M_BindHexenControls(void);
void M_BindStrifeControls(void);
void M_BindWeaponControls(void);
void M_BindMapControls(void);
void M_BindMenuControls(void);
void M_BindChatControls(unsigned int num_players);
void M_ApplyPlatformDefaults(void);
#endif /* #ifndef __M_CONTROLS_H__ */

57
apps/doom/m_fixed.c Normal file
View File

@ -0,0 +1,57 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Fixed point implementation.
//
#include "essence/include.h"
#include "doomtype.h"
#include "i_system.h"
#include "m_fixed.h"
// Fixme. __USE_C_FIXED__ or something.
fixed_t
FixedMul
( fixed_t a,
fixed_t b )
{
return ((int64_t) a * (int64_t) b) >> FRACBITS;
}
//
// FixedDiv, C version.
//
fixed_t FixedDiv(fixed_t a, fixed_t b)
{
if ((ES_abs(a) >> 14) >= ES_abs(b))
{
return (a^b) < 0 ? INT_MIN : INT_MAX;
}
else
{
int64_t result;
result = ((int64_t) a << 16) / b;
return (fixed_t) result;
}
}

39
apps/doom/m_fixed.h Normal file
View File

@ -0,0 +1,39 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Fixed point arithemtics, implementation.
//
#ifndef __M_FIXED__
#define __M_FIXED__
//
// Fixed point, 32bit as 16.16.
//
#define FRACBITS 16
#define FRACUNIT (1<<FRACBITS)
typedef int fixed_t;
fixed_t FixedMul (fixed_t a, fixed_t b);
fixed_t FixedDiv (fixed_t a, fixed_t b);
#endif

2119
apps/doom/m_menu.c Normal file

File diff suppressed because it is too large Load Diff

61
apps/doom/m_menu.h Normal file
View File

@ -0,0 +1,61 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Menu widget stuff, episode selection and such.
//
#ifndef __M_MENU__
#define __M_MENU__
#include "d_event.h"
//
// MENUS
//
// Called by main loop,
// saves config file and calls I_Quit when user exits.
// Even when the menu is not displayed,
// this can resize the view and change game parameters.
// Does all the real work of the menu interaction.
boolean M_Responder (event_t *ev);
// Called by main loop,
// only used for menu (skull cursor) animation.
void M_Ticker (void);
// Called by main loop,
// draws the menus directly into the screen buffer.
void M_Drawer (void);
// Called by D_DoomMain,
// loads the config file.
void M_Init (void);
// Called by intro code to force menu up upon a keypress,
// does nothing if menu is already up.
void M_StartControlPanel (void);
extern int detailLevel;
extern int screenblocks;
#endif

470
apps/doom/m_misc.c Normal file
View File

@ -0,0 +1,470 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 1993-2008 Raven Software
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Miscellaneous.
//
#include "essence/include.h"
#include "config.h"
#include "doomtype.h"
#include "i_swap.h"
#include "i_system.h"
#include "i_video.h"
#include "m_misc.h"
#include "v_video.h"
#include "w_wad.h"
#include "z_zone.h"
//
// Create a directory
//
void M_MakeDirectory(char *path)
{
ES_mkdir(path);
}
// Check if a file exists
boolean M_FileExists(char *filename)
{
ES_File *fstream;
fstream = ES_fopen(filename, ES_READ_MODE);
if (fstream != NULL)
{
ES_fclose(fstream);
return true;
}
else
{
return false;
}
}
//
// Determine the length of an open file.
//
long M_FileLength(ES_File *handle)
{
long savedpos;
long length;
// save the current position in the file
savedpos = ES_ftell(handle);
// jump to the end and find the length
ES_fseek(handle, 0, ES_SEEK_END);
length = ES_ftell(handle);
// go back to the old location
ES_fseek(handle, savedpos, ES_SEEK_SET);
return length;
}
//
// M_WriteFile
//
boolean M_WriteFile(char *name, void *source, int length)
{
ES_File *handle;
int count;
handle = ES_fopen(name, ES_WRITE_MODE | ES_BYTE_MODE);
if (handle == NULL) return false;
count = ES_fwrite(source, length, 1, handle);
ES_fclose(handle);
if (count < length)
return false;
return true;
}
//
// M_ReadFile
//
int M_ReadFile(char *name, byte **buffer)
{
ES_File *handle;
int count, length;
byte *buf;
handle = ES_fopen(name, ES_READ_MODE | ES_BYTE_MODE);
if (handle == NULL) I_Error ("Couldn't read file %s", name);
// find the size of the file by seeking to the end and
// reading the current position
length = M_FileLength(handle);
buf = Z_Malloc (length, PU_STATIC, NULL);
count = ES_fread(buf, length, 1, handle);
ES_fclose (handle);
if (count < length)
I_Error ("Couldn't read file %s", name);
*buffer = buf;
return length;
}
// Returns the path to a temporary file of the given name, stored
// inside the system temporary directory.
//
// The returned value must be freed with Z_Free after use.
char *M_TempFile(char *s)
{
return M_StringJoin(TMP_DIR, DIR_SEPARATOR_S, s, NULL);
}
boolean M_StrToInt(const char *str, int *result)
{
char *next = 0;
if (str[1] == '0' && (str[2] == 'x' || str[2] == 'X')) {
*result = (int)ES_strtol(str+3, &next, 16);
} else if (str[1] == '0') {
*result = (int)ES_strtol(str+3, &next, 8);
} else {
*result = (int)ES_strtol(str+3, &next, 10);
}
return next != 0 && next != str;
}
void M_ExtractFileBase(char *path, char *dest)
{
char *src;
char *filename;
int length;
src = path + ES_strlen(path) - 1;
// back up until a \ or the start
while (src != path && *(src - 1) != DIR_SEPARATOR)
{
src--;
}
filename = src;
// Copy up to eight characters
// Note: Vanilla Doom exits with an error if a filename is specified
// with a base of more than eight characters. To remove the 8.3
// filename limit, instead we simply truncate the name.
length = 0;
ES_memset(dest, 0, 8);
while (*src != '\0' && *src != '.')
{
if (length >= 8)
{
ES_warnf("Truncated '%s' lump name to '%.8s'.\n",
filename, dest);
break;
}
dest[length++] = ES_toupper((int)*src++);
}
}
//---------------------------------------------------------------------------
//
// PROC M_ForceUppercase
//
// Change string to uppercase.
//
//---------------------------------------------------------------------------
void M_ForceUppercase(char *text)
{
char *p;
for (p = text; *p != '\0'; ++p)
{
*p = ES_toupper(*p);
}
}
//
// M_StrCaseStr
//
// Case-insensitive version of strstr()
//
char *M_StrCaseStr(char *haystack, char *needle)
{
unsigned int haystack_len;
unsigned int needle_len;
unsigned int len;
unsigned int i;
haystack_len = ES_strlen(haystack);
needle_len = ES_strlen(needle);
if (haystack_len < needle_len)
{
return NULL;
}
len = haystack_len - needle_len;
for (i = 0; i <= len; ++i)
{
if (!ES_strncasecmp(haystack + i, needle, needle_len))
{
return haystack + i;
}
}
return NULL;
}
//
// Safe version of strdup() that checks the string was successfully
// allocated.
//
char *M_StringDuplicate(const char *orig)
{
char *result;
result = ES_strdup(orig);
if (result == NULL)
{
I_Error("Failed to duplicate string (length %i)\n",
ES_strlen(orig));
}
return result;
}
//
// String replace function.
//
char *M_StringReplace(const char *haystack, const char *needle,
const char *replacement)
{
char *result, *dst;
const char *p;
size_t needle_len = ES_strlen(needle);
size_t result_len, dst_len;
// Iterate through occurrences of 'needle' and calculate the size of
// the new string.
result_len = ES_strlen(haystack) + 1;
p = haystack;
for (;;)
{
p = ES_strstr(p, needle);
if (p == NULL)
{
break;
}
p += needle_len;
result_len += ES_strlen(replacement) - needle_len;
}
// Construct new string.
result = ES_malloc(result_len);
if (result == NULL)
{
I_Error("M_StringReplace: Failed to allocate new string");
return NULL;
}
dst = result; dst_len = result_len;
p = haystack;
while (*p != '\0')
{
if (!ES_strncmp(p, needle, needle_len))
{
M_StringCopy(dst, replacement, dst_len);
p += needle_len;
dst += ES_strlen(replacement);
dst_len -= ES_strlen(replacement);
}
else
{
*dst = *p;
++dst; --dst_len;
++p;
}
}
*dst = '\0';
return result;
}
// Safe string copy function that works like OpenBSD's strlcpy().
// Returns true if the string was not truncated.
boolean M_StringCopy(char *dest, const char *src, size_t dest_size)
{
size_t len;
if (dest_size >= 1)
{
dest[dest_size - 1] = '\0';
ES_strncpy(dest, src, dest_size - 1);
}
else
{
return false;
}
len = ES_strlen(dest);
return src[len] == '\0';
}
// Safe string concat function that works like OpenBSD's strlcat().
// Returns true if string not truncated.
boolean M_StringConcat(char *dest, const char *src, size_t dest_size)
{
size_t offset;
offset = ES_strlen(dest);
if (offset > dest_size)
{
offset = dest_size;
}
return M_StringCopy(dest + offset, src, dest_size - offset);
}
// Returns true if 's' begins with the specified prefix.
boolean M_StringStartsWith(const char *s, const char *prefix)
{
return ES_strlen(s) > ES_strlen(prefix)
&& ES_strncmp(s, prefix, ES_strlen(prefix)) == 0;
}
// Returns true if 's' ends with the specified suffix.
boolean M_StringEndsWith(const char *s, const char *suffix)
{
return ES_strlen(s) >= ES_strlen(suffix)
&& ES_strcmp(s + ES_strlen(s) - ES_strlen(suffix), suffix) == 0;
}
// Return a newly-malloced string with all the strings given as arguments
// concatenated together.
char *M_StringJoin(const char *s, ...)
{
char *result;
const char *v;
va_list args;
size_t result_len;
result_len = ES_strlen(s) + 1;
va_start(args, s);
for (;;)
{
v = va_arg(args, const char *);
if (v == NULL)
{
break;
}
result_len += ES_strlen(v);
}
va_end(args);
result = ES_malloc(result_len);
if (result == NULL)
{
I_Error("M_StringJoin: Failed to allocate new string.");
return NULL;
}
M_StringCopy(result, s, result_len);
va_start(args, s);
for (;;)
{
v = va_arg(args, const char *);
if (v == NULL)
{
break;
}
M_StringConcat(result, v, result_len);
}
va_end(args);
return result;
}
// Safe, portable vsnprintf().
int M_vsnprintf(char *buf, size_t buf_len, const char *s, va_list args)
{
size_t result;
if (buf_len < 1)
{
return 0;
}
// Windows (and other OSes?) has a vsnprintf() that doesn't always
// append a trailing \0. So we must do it, and write into a buffer
// that is one byte shorter; otherwise this function is unsafe.
result = ES_vsnprintf(buf, buf_len, s, args);
// If truncated, change the final char in the buffer to a \0.
// A negative result indicates a truncated buffer on Windows.
if (result < 0 || result >= buf_len)
{
buf[buf_len - 1] = '\0';
result = buf_len - 1;
}
return result;
}
// Safe, portable snprintf().
int M_snprintf(char *buf, size_t buf_len, const char *s, ...)
{
va_list args;
int result;
va_start(args, s);
result = M_vsnprintf(buf, buf_len, s, args);
va_end(args);
return result;
}

50
apps/doom/m_misc.h Normal file
View File

@ -0,0 +1,50 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Miscellaneous.
//
#ifndef __M_MISC__
#define __M_MISC__
#include "essence/include.h"
#include "doomtype.h"
boolean M_WriteFile(char *name, void *source, int length);
int M_ReadFile(char *name, byte **buffer);
void M_MakeDirectory(char *dir);
char *M_TempFile(char *s);
boolean M_FileExists(char *file);
long M_FileLength(ES_File *handle);
boolean M_StrToInt(const char *str, int *result);
void M_ExtractFileBase(char *path, char *dest);
void M_ForceUppercase(char *text);
char *M_StrCaseStr(char *haystack, char *needle);
char *M_StringDuplicate(const char *orig);
boolean M_StringCopy(char *dest, const char *src, size_t dest_size);
boolean M_StringConcat(char *dest, const char *src, size_t dest_size);
char *M_StringReplace(const char *haystack, const char *needle,
const char *replacement);
char *M_StringJoin(const char *s, ...);
boolean M_StringStartsWith(const char *s, const char *prefix);
boolean M_StringEndsWith(const char *s, const char *suffix);
int M_vsnprintf(char *buf, size_t buf_len, const char *s, va_list args);
int M_snprintf(char *buf, size_t buf_len, const char *s, ...);
char *M_OEMToUTF8(const char *ansi);
#endif

65
apps/doom/m_random.c Normal file
View File

@ -0,0 +1,65 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Random number LUT.
//
//
// M_Random
// Returns a 0-255 number
//
static const unsigned char rndtable[256] = {
0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66 ,
74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36 ,
95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188 ,
52, 140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224 ,
149, 104, 25, 178, 252, 182, 202, 182, 141, 197, 4, 81, 181, 242 ,
145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, 249, 0 ,
175, 143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235 ,
25, 92, 20, 145, 138, 77, 69, 166, 78, 176, 173, 212, 166, 113 ,
94, 161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, 171, 75 ,
136, 156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196 ,
135, 106, 63, 197, 195, 86, 96, 203, 113, 101, 170, 247, 181, 113 ,
80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112, 166, 103, 241 ,
24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224 ,
145, 224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95 ,
28, 139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226 ,
71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36 ,
17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106 ,
197, 242, 98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136 ,
120, 163, 236, 249
};
int rndindex = 0;
int prndindex = 0;
// Which one is deterministic?
int P_Random (void)
{
prndindex = (prndindex+1)&0xff;
return rndtable[prndindex];
}
int M_Random (void)
{
rndindex = (rndindex+1)&0xff;
return rndtable[rndindex];
}
void M_ClearRandom (void)
{
rndindex = prndindex = 0;
}

39
apps/doom/m_random.h Normal file
View File

@ -0,0 +1,39 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
//
//
#ifndef __M_RANDOM__
#define __M_RANDOM__
#include "doomtype.h"
// Returns a number from 0 to 255,
// from a lookup table.
int M_Random (void);
// As M_Random, but used only by the play simulation.
int P_Random (void);
// Fix randoms for demos.
void M_ClearRandom (void);
#endif

195
apps/doom/memio.c Normal file
View File

@ -0,0 +1,195 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// Emulates the IO functions in C stdio.h reading and writing to
// memory.
//
#include "essence/include.h"
#include "memio.h"
#include "z_zone.h"
typedef enum {
MODE_READ,
MODE_WRITE,
} memfile_mode_t;
struct _MEMFILE {
unsigned char *buf;
size_t buflen;
size_t alloced;
unsigned int position;
memfile_mode_t mode;
};
// Open a memory area for reading
MEMFILE *mem_fopen_read(void *buf, size_t buflen)
{
MEMFILE *file;
file = Z_Malloc(sizeof(MEMFILE), PU_STATIC, 0);
file->buf = (unsigned char *) buf;
file->buflen = buflen;
file->position = 0;
file->mode = MODE_READ;
return file;
}
// Read bytes
size_t mem_fread(void *buf, size_t size, size_t nmemb, MEMFILE *stream)
{
size_t items;
if (stream->mode != MODE_READ)
{
ES_debugf("not a read stream\n");
return -1;
}
// Trying to read more bytes than we have left?
items = nmemb;
if (items * size > stream->buflen - stream->position)
{
items = (stream->buflen - stream->position) / size;
}
// Copy bytes to buffer
ES_memcpy(buf, stream->buf + stream->position, items * size);
// Update position
stream->position += items * size;
return items;
}
// Open a memory area for writing
MEMFILE *mem_fopen_write(void)
{
MEMFILE *file;
file = Z_Malloc(sizeof(MEMFILE), PU_STATIC, 0);
file->alloced = 1024;
file->buf = Z_Malloc(file->alloced, PU_STATIC, 0);
file->buflen = 0;
file->position = 0;
file->mode = MODE_WRITE;
return file;
}
// Write bytes to stream
size_t mem_fwrite(const void *ptr, size_t size, size_t nmemb, MEMFILE *stream)
{
size_t bytes;
if (stream->mode != MODE_WRITE)
{
return -1;
}
// More bytes than can fit in the buffer?
// If so, reallocate bigger.
bytes = size * nmemb;
while (bytes > stream->alloced - stream->position)
{
unsigned char *newbuf;
newbuf = Z_Malloc(stream->alloced * 2, PU_STATIC, 0);
ES_memcpy(newbuf, stream->buf, stream->alloced);
Z_Free(stream->buf);
stream->buf = newbuf;
stream->alloced *= 2;
}
// Copy into buffer
ES_memcpy(stream->buf + stream->position, ptr, bytes);
stream->position += bytes;
if (stream->position > stream->buflen)
stream->buflen = stream->position;
return nmemb;
}
void mem_get_buf(MEMFILE *stream, void **buf, size_t *buflen)
{
*buf = stream->buf;
*buflen = stream->buflen;
}
void mem_fclose(MEMFILE *stream)
{
if (stream->mode == MODE_WRITE)
{
Z_Free(stream->buf);
}
Z_Free(stream);
}
long mem_ftell(MEMFILE *stream)
{
return stream->position;
}
int mem_fseek(MEMFILE *stream, signed long position, mem_rel_t whence)
{
unsigned int newpos;
switch (whence)
{
case MEM_SEEK_SET:
newpos = (int) position;
break;
case MEM_SEEK_CUR:
newpos = (int) (stream->position + position);
break;
case MEM_SEEK_END:
newpos = (int) (stream->buflen + position);
break;
default:
return -1;
}
if (newpos < stream->buflen)
{
stream->position = newpos;
return 0;
}
else
{
ES_debugf("Error seeking to %i\n", newpos);
return -1;
}
}

38
apps/doom/memio.h Normal file
View File

@ -0,0 +1,38 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef MEMIO_H
#define MEMIO_H
typedef struct _MEMFILE MEMFILE;
typedef enum
{
MEM_SEEK_SET,
MEM_SEEK_CUR,
MEM_SEEK_END,
} mem_rel_t;
MEMFILE *mem_fopen_read(void *buf, size_t buflen);
size_t mem_fread(void *buf, size_t size, size_t nmemb, MEMFILE *stream);
MEMFILE *mem_fopen_write(void);
size_t mem_fwrite(const void *ptr, size_t size, size_t nmemb, MEMFILE *stream);
void mem_get_buf(MEMFILE *stream, void **buf, size_t *buflen);
void mem_fclose(MEMFILE *stream);
long mem_ftell(MEMFILE *stream);
int mem_fseek(MEMFILE *stream, signed long offset, mem_rel_t whence);
#endif /* #ifndef MEMIO_H */

693
apps/doom/mus2mid.c Normal file
View File

@ -0,0 +1,693 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
// Copyright(C) 2006 Ben Ryves 2006
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// mus2mid.c - Ben Ryves 2006 - http://benryves.com - benryves@benryves.com
// Use to convert a MUS file into a single track, type 0 MIDI file.
#include "essence/include.h"
#include "doomtype.h"
#include "i_swap.h"
#include "memio.h"
#include "mus2mid.h"
#define NUM_CHANNELS 16
#define MIDI_PERCUSSION_CHAN 9
#define MUS_PERCUSSION_CHAN 15
// MUS event codes
typedef enum
{
mus_releasekey = 0x00,
mus_presskey = 0x10,
mus_pitchwheel = 0x20,
mus_systemevent = 0x30,
mus_changecontroller = 0x40,
mus_scoreend = 0x60
} musevent;
// MIDI event codes
typedef enum
{
midi_releasekey = 0x80,
midi_presskey = 0x90,
midi_aftertouchkey = 0xA0,
midi_changecontroller = 0xB0,
midi_changepatch = 0xC0,
midi_aftertouchchannel = 0xD0,
midi_pitchwheel = 0xE0
} midievent;
// Structure to hold MUS file header
typedef struct
{
byte id[4];
unsigned short scorelength;
unsigned short scorestart;
unsigned short primarychannels;
unsigned short secondarychannels;
unsigned short instrumentcount;
} musheader;
// Standard MIDI type 0 header + track header
static const byte midiheader[] =
{
'M', 'T', 'h', 'd', // Main header
0x00, 0x00, 0x00, 0x06, // Header size
0x00, 0x00, // MIDI type (0)
0x00, 0x01, // Number of tracks
0x00, 0x46, // Resolution
'M', 'T', 'r', 'k', // Start of track
0x00, 0x00, 0x00, 0x00 // Placeholder for track length
};
// Cached channel velocities
static byte channelvelocities[] =
{
127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127
};
// Timestamps between sequences of MUS events
static unsigned int queuedtime = 0;
// Counter for the length of the track
static unsigned int tracksize;
static const byte controller_map[] =
{
0x00, 0x20, 0x01, 0x07, 0x0A, 0x0B, 0x5B, 0x5D,
0x40, 0x43, 0x78, 0x7B, 0x7E, 0x7F, 0x79
};
static int channel_map[NUM_CHANNELS];
// Write timestamp to a MIDI file.
static boolean WriteTime(unsigned int time, MEMFILE *midioutput)
{
unsigned int buffer = time & 0x7F;
byte writeval;
while ((time >>= 7) != 0)
{
buffer <<= 8;
buffer |= ((time & 0x7F) | 0x80);
}
for (;;)
{
writeval = (byte)(buffer & 0xFF);
if (mem_fwrite(&writeval, 1, 1, midioutput) != 1)
{
return true;
}
++tracksize;
if ((buffer & 0x80) != 0)
{
buffer >>= 8;
}
else
{
queuedtime = 0;
return false;
}
}
}
// Write the end of track marker
static boolean WriteEndTrack(MEMFILE *midioutput)
{
byte endtrack[] = {0xFF, 0x2F, 0x00};
if (WriteTime(queuedtime, midioutput))
{
return true;
}
if (mem_fwrite(endtrack, 1, 3, midioutput) != 3)
{
return true;
}
tracksize += 3;
return false;
}
// Write a key press event
static boolean WritePressKey(byte channel, byte key,
byte velocity, MEMFILE *midioutput)
{
byte working = midi_presskey | channel;
if (WriteTime(queuedtime, midioutput))
{
return true;
}
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
{
return true;
}
working = key & 0x7F;
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
{
return true;
}
working = velocity & 0x7F;
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
{
return true;
}
tracksize += 3;
return false;
}
// Write a key release event
static boolean WriteReleaseKey(byte channel, byte key,
MEMFILE *midioutput)
{
byte working = midi_releasekey | channel;
if (WriteTime(queuedtime, midioutput))
{
return true;
}
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
{
return true;
}
working = key & 0x7F;
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
{
return true;
}
working = 0;
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
{
return true;
}
tracksize += 3;
return false;
}
// Write a pitch wheel/bend event
static boolean WritePitchWheel(byte channel, short wheel,
MEMFILE *midioutput)
{
byte working = midi_pitchwheel | channel;
if (WriteTime(queuedtime, midioutput))
{
return true;
}
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
{
return true;
}
working = wheel & 0x7F;
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
{
return true;
}
working = (wheel >> 7) & 0x7F;
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
{
return true;
}
tracksize += 3;
return false;
}
// Write a patch change event
static boolean WriteChangePatch(byte channel, byte patch,
MEMFILE *midioutput)
{
byte working = midi_changepatch | channel;
if (WriteTime(queuedtime, midioutput))
{
return true;
}
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
{
return true;
}
working = patch & 0x7F;
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
{
return true;
}
tracksize += 2;
return false;
}
// Write a valued controller change event
static boolean WriteChangeController_Valued(byte channel,
byte control,
byte value,
MEMFILE *midioutput)
{
byte working = midi_changecontroller | channel;
if (WriteTime(queuedtime, midioutput))
{
return true;
}
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
{
return true;
}
working = control & 0x7F;
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
{
return true;
}
// Quirk in vanilla DOOM? MUS controller values should be
// 7-bit, not 8-bit.
working = value;// & 0x7F;
// Fix on said quirk to stop MIDI players from complaining that
// the value is out of range:
if (working & 0x80)
{
working = 0x7F;
}
if (mem_fwrite(&working, 1, 1, midioutput) != 1)
{
return true;
}
tracksize += 3;
return false;
}
// Write a valueless controller change event
static boolean WriteChangeController_Valueless(byte channel,
byte control,
MEMFILE *midioutput)
{
return WriteChangeController_Valued(channel, control, 0,
midioutput);
}
// Allocate a free MIDI channel.
static int AllocateMIDIChannel(void)
{
int result;
int max;
int i;
// Find the current highest-allocated channel.
max = -1;
for (i=0; i<NUM_CHANNELS; ++i)
{
if (channel_map[i] > max)
{
max = channel_map[i];
}
}
// max is now equal to the highest-allocated MIDI channel. We can
// now allocate the next available channel. This also works if
// no channels are currently allocated (max=-1)
result = max + 1;
// Don't allocate the MIDI percussion channel!
if (result == MIDI_PERCUSSION_CHAN)
{
++result;
}
return result;
}
// Given a MUS channel number, get the MIDI channel number to use
// in the outputted file.
static int GetMIDIChannel(int mus_channel, MEMFILE *midioutput)
{
// Find the MIDI channel to use for this MUS channel.
// MUS channel 15 is the percusssion channel.
if (mus_channel == MUS_PERCUSSION_CHAN)
{
return MIDI_PERCUSSION_CHAN;
}
else
{
// If a MIDI channel hasn't been allocated for this MUS channel
// yet, allocate the next free MIDI channel.
if (channel_map[mus_channel] == -1)
{
channel_map[mus_channel] = AllocateMIDIChannel();
// First time using the channel, send an "all notes off"
// event. This fixes "The D_DDTBLU disease" described here:
// https://www.doomworld.com/vb/source-ports/66802-the
WriteChangeController_Valueless(channel_map[mus_channel], 0x7b,
midioutput);
}
return channel_map[mus_channel];
}
}
static boolean ReadMusHeader(MEMFILE *file, musheader *header)
{
boolean result;
result = mem_fread(&header->id, sizeof(byte), 4, file) == 4
&& mem_fread(&header->scorelength, sizeof(short), 1, file) == 1
&& mem_fread(&header->scorestart, sizeof(short), 1, file) == 1
&& mem_fread(&header->primarychannels, sizeof(short), 1, file) == 1
&& mem_fread(&header->secondarychannels, sizeof(short), 1, file) == 1
&& mem_fread(&header->instrumentcount, sizeof(short), 1, file) == 1;
if (result)
{
header->scorelength = SHORT(header->scorelength);
header->scorestart = SHORT(header->scorestart);
header->primarychannels = SHORT(header->primarychannels);
header->secondarychannels = SHORT(header->secondarychannels);
header->instrumentcount = SHORT(header->instrumentcount);
}
return result;
}
// Read a MUS file from a stream (musinput) and output a MIDI file to
// a stream (midioutput).
//
// Returns 0 on success or 1 on failure.
boolean mus2mid(MEMFILE *musinput, MEMFILE *midioutput)
{
// Header for the MUS file
musheader musfileheader;
// Descriptor for the current MUS event
byte eventdescriptor;
int channel; // Channel number
musevent event;
// Bunch of vars read from MUS lump
byte key;
byte controllernumber;
byte controllervalue;
// Buffer used for MIDI track size record
byte tracksizebuffer[4];
// Flag for when the score end marker is hit.
int hitscoreend = 0;
// Temp working byte
byte working;
// Used in building up time delays
unsigned int timedelay;
// Initialise channel map to mark all channels as unused.
for (channel=0; channel<NUM_CHANNELS; ++channel)
{
channel_map[channel] = -1;
}
// Grab the header
if (!ReadMusHeader(musinput, &musfileheader))
{
return true;
}
// [crispy] enable MUS format header check
#define CHECK_MUS_HEADER
#ifdef CHECK_MUS_HEADER
// Check MUS header
if (musfileheader.id[0] != 'M'
|| musfileheader.id[1] != 'U'
|| musfileheader.id[2] != 'S'
|| musfileheader.id[3] != 0x1A)
{
return true;
}
#endif
// Seek to where the data is held
if (mem_fseek(musinput, (long)musfileheader.scorestart,
MEM_SEEK_SET) != 0)
{
return true;
}
// So, we can assume the MUS file is faintly legit. Let's start
// writing MIDI data...
mem_fwrite(midiheader, 1, sizeof(midiheader), midioutput);
tracksize = 0;
// Now, process the MUS file:
while (!hitscoreend)
{
// Handle a block of events:
while (!hitscoreend)
{
// Fetch channel number and event code:
if (mem_fread(&eventdescriptor, 1, 1, musinput) != 1)
{
return true;
}
channel = GetMIDIChannel(eventdescriptor & 0x0F, midioutput);
event = eventdescriptor & 0x70;
switch (event)
{
case mus_releasekey:
if (mem_fread(&key, 1, 1, musinput) != 1)
{
return true;
}
if (WriteReleaseKey(channel, key, midioutput))
{
return true;
}
break;
case mus_presskey:
if (mem_fread(&key, 1, 1, musinput) != 1)
{
return true;
}
if (key & 0x80)
{
if (mem_fread(&channelvelocities[channel], 1, 1, musinput) != 1)
{
return true;
}
channelvelocities[channel] &= 0x7F;
}
if (WritePressKey(channel, key,
channelvelocities[channel], midioutput))
{
return true;
}
break;
case mus_pitchwheel:
if (mem_fread(&key, 1, 1, musinput) != 1)
{
break;
}
if (WritePitchWheel(channel, (short)(key * 64), midioutput))
{
return true;
}
break;
case mus_systemevent:
if (mem_fread(&controllernumber, 1, 1, musinput) != 1)
{
return true;
}
if (controllernumber < 10 || controllernumber > 14)
{
return true;
}
if (WriteChangeController_Valueless(channel,
controller_map[controllernumber],
midioutput))
{
return true;
}
break;
case mus_changecontroller:
if (mem_fread(&controllernumber, 1, 1, musinput) != 1)
{
return true;
}
if (mem_fread(&controllervalue, 1, 1, musinput) != 1)
{
return true;
}
if (controllernumber == 0)
{
if (WriteChangePatch(channel, controllervalue,
midioutput))
{
return true;
}
}
else
{
if (controllernumber < 1 || controllernumber > 9)
{
return true;
}
if (WriteChangeController_Valued(channel,
controller_map[controllernumber],
controllervalue,
midioutput))
{
return true;
}
}
break;
case mus_scoreend:
hitscoreend = 1;
break;
default:
return true;
break;
}
if (eventdescriptor & 0x80)
{
break;
}
}
// Now we need to read the time code:
if (!hitscoreend)
{
timedelay = 0;
for (;;)
{
if (mem_fread(&working, 1, 1, musinput) != 1)
{
return true;
}
timedelay = timedelay * 128 + (working & 0x7F);
if ((working & 0x80) == 0)
{
break;
}
}
queuedtime += timedelay;
}
}
// End of track
if (WriteEndTrack(midioutput))
{
return true;
}
// Write the track size into the stream
if (mem_fseek(midioutput, 18, MEM_SEEK_SET))
{
return true;
}
tracksizebuffer[0] = (tracksize >> 24) & 0xff;
tracksizebuffer[1] = (tracksize >> 16) & 0xff;
tracksizebuffer[2] = (tracksize >> 8) & 0xff;
tracksizebuffer[3] = tracksize & 0xff;
if (mem_fwrite(tracksizebuffer, 1, 4, midioutput) != 4)
{
return true;
}
return false;
}

9
apps/doom/mus2mid.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef MUS2MID_H
#define MUS2MID_H
#include "doomtype.h"
#include "memio.h"
boolean mus2mid(MEMFILE *musinput, MEMFILE *midioutput);
#endif /* #ifndef MUS2MID_H */

4
apps/doom/net_client.c Normal file
View File

@ -0,0 +1,4 @@
#include "net_client.h"
boolean net_client_connected = false;
boolean drone = false;

50
apps/doom/net_client.h Normal file
View File

@ -0,0 +1,50 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// Network client code
//
#ifndef NET_CLIENT_H
#define NET_CLIENT_H
#include "doomtype.h"
#include "d_ticcmd.h"
#include "sha1.h"
#include "net_defs.h"
boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data);
void NET_CL_Disconnect(void);
void NET_CL_Run(void);
void NET_CL_Init(void);
void NET_CL_LaunchGame(void);
void NET_CL_StartGame(net_gamesettings_t *settings);
void NET_CL_SendTiccmd(ticcmd_t *ticcmd, int maketic);
boolean NET_CL_GetSettings(net_gamesettings_t *_settings);
void NET_Init(void);
void NET_BindVariables(void);
extern boolean net_client_connected;
extern boolean net_client_received_wait_data;
extern net_waitdata_t net_client_wait_data;
extern boolean net_waiting_for_launch;
extern char *net_player_name;
extern sha1_digest_t net_server_wad_sha1sum;
extern unsigned int net_server_is_freedoom;
extern sha1_digest_t net_local_wad_sha1sum;
extern unsigned int net_local_is_freedoom;
extern boolean drone;
#endif /* #ifndef NET_CLIENT_H */

25
apps/doom/net_dedicated.h Normal file
View File

@ -0,0 +1,25 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// Dedicated server code.
//
#ifndef NET_DEDICATED_H
#define NET_DEDICATED_H
void NET_DedicatedServer(void);
#endif /* #ifndef NET_DEDICATED_H */

246
apps/doom/net_defs.h Normal file
View File

@ -0,0 +1,246 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Definitions for use in networking code.
//
#ifndef NET_DEFS_H
#define NET_DEFS_H
#include "essence/include.h"
#include "doomtype.h"
#include "d_ticcmd.h"
#include "sha1.h"
// Absolute maximum number of "nodes" in the game. This is different to
// NET_MAXPLAYERS, as there may be observers that are not participating
// (eg. left/right monitors)
#define MAXNETNODES 16
// The maximum number of players, multiplayer/networking.
// This is the maximum supported by the networking code; individual games
// have their own values for MAXPLAYERS that can be smaller.
#define NET_MAXPLAYERS 8
// Maximum length of a player's name.
#define MAXPLAYERNAME 30
// Networking and tick handling related.
#define BACKUPTICS 128
typedef struct _net_module_s net_module_t;
typedef struct _net_packet_s net_packet_t;
typedef struct _net_addr_s net_addr_t;
typedef struct _net_context_s net_context_t;
struct _net_packet_s
{
byte *data;
size_t len;
size_t alloced;
unsigned int pos;
};
struct _net_module_s
{
// Initialize this module for use as a client
boolean (*InitClient)(void);
// Initialize this module for use as a server
boolean (*InitServer)(void);
// Send a packet
void (*SendPacket)(net_addr_t *addr, net_packet_t *packet);
// Check for new packets to receive
//
// Returns true if packet received
boolean (*RecvPacket)(net_addr_t **addr, net_packet_t **packet);
// Converts an address to a string
void (*AddrToString)(net_addr_t *addr, char *buffer, int buffer_len);
// Free back an address when no longer in use
void (*FreeAddress)(net_addr_t *addr);
// Try to resolve a name to an address
net_addr_t *(*ResolveAddress)(char *addr);
};
// net_addr_t
struct _net_addr_s
{
net_module_t *module;
void *handle;
};
// magic number sent when connecting to check this is a valid client
#define NET_MAGIC_NUMBER 3436803284U
// header field value indicating that the packet is a reliable packet
#define NET_RELIABLE_PACKET (1 << 15)
// packet types
typedef enum
{
NET_PACKET_TYPE_SYN,
NET_PACKET_TYPE_ACK,
NET_PACKET_TYPE_REJECTED,
NET_PACKET_TYPE_KEEPALIVE,
NET_PACKET_TYPE_WAITING_DATA,
NET_PACKET_TYPE_GAMESTART,
NET_PACKET_TYPE_GAMEDATA,
NET_PACKET_TYPE_GAMEDATA_ACK,
NET_PACKET_TYPE_DISCONNECT,
NET_PACKET_TYPE_DISCONNECT_ACK,
NET_PACKET_TYPE_RELIABLE_ACK,
NET_PACKET_TYPE_GAMEDATA_RESEND,
NET_PACKET_TYPE_CONSOLE_MESSAGE,
NET_PACKET_TYPE_QUERY,
NET_PACKET_TYPE_QUERY_RESPONSE,
NET_PACKET_TYPE_LAUNCH,
} net_packet_type_t;
typedef enum
{
NET_MASTER_PACKET_TYPE_ADD,
NET_MASTER_PACKET_TYPE_ADD_RESPONSE,
NET_MASTER_PACKET_TYPE_QUERY,
NET_MASTER_PACKET_TYPE_QUERY_RESPONSE,
NET_MASTER_PACKET_TYPE_GET_METADATA,
NET_MASTER_PACKET_TYPE_GET_METADATA_RESPONSE,
NET_MASTER_PACKET_TYPE_SIGN_START,
NET_MASTER_PACKET_TYPE_SIGN_START_RESPONSE,
NET_MASTER_PACKET_TYPE_SIGN_END,
NET_MASTER_PACKET_TYPE_SIGN_END_RESPONSE,
} net_master_packet_type_t;
// Settings specified when the client connects to the server.
typedef struct
{
int gamemode;
int gamemission;
int lowres_turn;
int drone;
int max_players;
int is_freedoom;
sha1_digest_t wad_sha1sum;
int player_class;
} net_connect_data_t;
// Game settings sent by client to server when initiating game start,
// and received from the server by clients when the game starts.
typedef struct
{
int ticdup;
int extratics;
int deathmatch;
int episode;
int nomonsters;
int fast_monsters;
int respawn_monsters;
int map;
int skill;
int gameversion;
int lowres_turn;
int new_sync;
int timelimit;
int loadgame;
int random; // [Strife only]
// These fields are only used by the server when sending a game
// start message:
int num_players;
int consoleplayer;
// Hexen player classes:
int player_classes[NET_MAXPLAYERS];
} net_gamesettings_t;
#define NET_TICDIFF_FORWARD (1 << 0)
#define NET_TICDIFF_SIDE (1 << 1)
#define NET_TICDIFF_TURN (1 << 2)
#define NET_TICDIFF_BUTTONS (1 << 3)
#define NET_TICDIFF_CONSISTANCY (1 << 4)
#define NET_TICDIFF_CHATCHAR (1 << 5)
#define NET_TICDIFF_RAVEN (1 << 6)
#define NET_TICDIFF_STRIFE (1 << 7)
typedef struct
{
unsigned int diff;
ticcmd_t cmd;
} net_ticdiff_t;
// Complete set of ticcmds from all players
typedef struct
{
signed int latency;
unsigned int seq;
boolean playeringame[NET_MAXPLAYERS];
net_ticdiff_t cmds[NET_MAXPLAYERS];
} net_full_ticcmd_t;
// Data sent in response to server queries
typedef struct
{
char *version;
int server_state;
int num_players;
int max_players;
int gamemode;
int gamemission;
char *description;
} net_querydata_t;
// Data sent by the server while waiting for the game to start.
typedef struct
{
int num_players;
int num_drones;
int ready_players;
int max_players;
int is_controller;
int consoleplayer;
char player_names[NET_MAXPLAYERS][MAXPLAYERNAME];
char player_addrs[NET_MAXPLAYERS][MAXPLAYERNAME];
sha1_digest_t wad_sha1sum;
int is_freedoom;
} net_waitdata_t;
#endif /* #ifndef NET_DEFS_H */

29
apps/doom/net_gui.h Normal file
View File

@ -0,0 +1,29 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// Graphical stuff related to the networking code:
//
// * The client waiting screen when we are waiting for the server to
// start the game.
//
#ifndef NET_GUI_H
#define NET_GUI_H
#include "doomtype.h"
extern void NET_WaitForLaunch(void);
#endif /* #ifndef NET_GUI_H */

36
apps/doom/net_io.h Normal file
View File

@ -0,0 +1,36 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Network packet manipulation (net_packet_t)
//
#ifndef NET_IO_H
#define NET_IO_H
#include "net_defs.h"
extern net_addr_t net_broadcast_addr;
net_context_t *NET_NewContext(void);
void NET_AddModule(net_context_t *context, net_module_t *module);
void NET_SendPacket(net_addr_t *addr, net_packet_t *packet);
void NET_SendBroadcast(net_context_t *context, net_packet_t *packet);
boolean NET_RecvPacket(net_context_t *context, net_addr_t **addr,
net_packet_t **packet);
char *NET_AddrToString(net_addr_t *addr);
void NET_FreeAddress(net_addr_t *addr);
net_addr_t *NET_ResolveAddress(net_context_t *context, char *address);
#endif /* #ifndef NET_IO_H */

27
apps/doom/net_loop.h Normal file
View File

@ -0,0 +1,27 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Loopback network module for server compiled into the client
//
#ifndef NET_LOOP_H
#define NET_LOOP_H
#include "net_defs.h"
extern net_module_t net_loop_client_module;
extern net_module_t net_loop_server_module;
#endif /* #ifndef NET_LOOP_H */

44
apps/doom/net_packet.h Normal file
View File

@ -0,0 +1,44 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Definitions for use in networking code.
//
#ifndef NET_PACKET_H
#define NET_PACKET_H
#include "net_defs.h"
net_packet_t *NET_NewPacket(int initial_size);
net_packet_t *NET_PacketDup(net_packet_t *packet);
void NET_FreePacket(net_packet_t *packet);
boolean NET_ReadInt8(net_packet_t *packet, unsigned int *data);
boolean NET_ReadInt16(net_packet_t *packet, unsigned int *data);
boolean NET_ReadInt32(net_packet_t *packet, unsigned int *data);
boolean NET_ReadSInt8(net_packet_t *packet, signed int *data);
boolean NET_ReadSInt16(net_packet_t *packet, signed int *data);
boolean NET_ReadSInt32(net_packet_t *packet, signed int *data);
char *NET_ReadString(net_packet_t *packet);
void NET_WriteInt8(net_packet_t *packet, unsigned int i);
void NET_WriteInt16(net_packet_t *packet, unsigned int i);
void NET_WriteInt32(net_packet_t *packet, unsigned int i);
void NET_WriteString(net_packet_t *packet, char *string);
#endif /* #ifndef NET_PACKET_H */

44
apps/doom/net_query.h Normal file
View File

@ -0,0 +1,44 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Querying servers to find their current status.
//
#ifndef NET_QUERY_H
#define NET_QUERY_H
#include "net_defs.h"
typedef void (*net_query_callback_t)(net_addr_t *addr,
net_querydata_t *querydata,
unsigned int ping_time,
void *user_data);
extern int NET_StartLANQuery(void);
extern int NET_StartMasterQuery(void);
extern void NET_LANQuery(void);
extern void NET_MasterQuery(void);
extern void NET_QueryAddress(char *addr);
extern net_addr_t *NET_FindLANServer(void);
extern int NET_Query_Poll(net_query_callback_t callback, void *user_data);
extern net_addr_t *NET_Query_ResolveMaster(net_context_t *context);
extern void NET_Query_AddToMaster(net_addr_t *master_addr);
extern boolean NET_Query_CheckAddedToMaster(boolean *result);
extern void NET_Query_MasterResponse(net_packet_t *packet);
#endif /* #ifndef NET_QUERY_H */

42
apps/doom/net_server.h Normal file
View File

@ -0,0 +1,42 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// Network server code
//
#ifndef NET_SERVER_H
#define NET_SERVER_H
// initialize server and wait for connections
void NET_SV_Init(void);
// run server: check for new packets received etc.
void NET_SV_Run(void);
// Shut down the server
// Blocks until all clients disconnect, or until a 5 second timeout
void NET_SV_Shutdown(void);
// Add a network module to the context used by the server
void NET_SV_AddModule(net_module_t *module);
// Register server with master server.
void NET_SV_RegisterWithMaster(void);
#endif /* #ifndef NET_SERVER_H */

328
apps/doom/p_ceilng.c Normal file
View File

@ -0,0 +1,328 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION: Ceiling aninmation (lowering, crushing, raising)
//
#include "z_zone.h"
#include "doomdef.h"
#include "p_local.h"
#include "s_sound.h"
// State.
#include "doomstat.h"
#include "r_state.h"
// Data.
#include "sounds.h"
//
// CEILINGS
//
ceiling_t* activeceilings[MAXCEILINGS];
//
// T_MoveCeiling
//
void T_MoveCeiling (ceiling_t* ceiling)
{
result_e res;
switch(ceiling->direction)
{
case 0:
// IN STASIS
break;
case 1:
// UP
res = T_MovePlane(ceiling->sector,
ceiling->speed,
ceiling->topheight,
false,1,ceiling->direction);
if (!(leveltime&7))
{
switch(ceiling->type)
{
case silentCrushAndRaise:
break;
default:
S_StartSound(&ceiling->sector->soundorg, sfx_stnmov);
// ?
break;
}
}
if (res == pastdest)
{
switch(ceiling->type)
{
case raiseToHighest:
P_RemoveActiveCeiling(ceiling);
break;
case silentCrushAndRaise:
S_StartSound(&ceiling->sector->soundorg, sfx_pstop);
// fall through
case fastCrushAndRaise:
case crushAndRaise:
ceiling->direction = -1;
break;
default:
break;
}
}
break;
case -1:
// DOWN
res = T_MovePlane(ceiling->sector,
ceiling->speed,
ceiling->bottomheight,
ceiling->crush,1,ceiling->direction);
if (!(leveltime&7))
{
switch(ceiling->type)
{
case silentCrushAndRaise: break;
default:
S_StartSound(&ceiling->sector->soundorg, sfx_stnmov);
}
}
if (res == pastdest)
{
switch(ceiling->type)
{
case silentCrushAndRaise:
S_StartSound(&ceiling->sector->soundorg, sfx_pstop);
// fall through
case crushAndRaise:
ceiling->speed = CEILSPEED;
// fall through
case fastCrushAndRaise:
ceiling->direction = 1;
break;
case lowerAndCrush:
case lowerToFloor:
P_RemoveActiveCeiling(ceiling);
break;
default:
break;
}
}
else // ( res != pastdest )
{
if (res == crushed)
{
switch(ceiling->type)
{
case silentCrushAndRaise:
case crushAndRaise:
case lowerAndCrush:
ceiling->speed = CEILSPEED / 8;
break;
default:
break;
}
}
}
break;
}
}
//
// EV_DoCeiling
// Move a ceiling up/down and all around!
//
int
EV_DoCeiling
( line_t* line,
ceiling_e type )
{
int secnum;
int rtn;
sector_t* sec;
ceiling_t* ceiling;
secnum = -1;
rtn = 0;
// Reactivate in-stasis ceilings...for certain types.
switch(type)
{
case fastCrushAndRaise:
case silentCrushAndRaise:
case crushAndRaise:
P_ActivateInStasisCeiling(line);
default:
break;
}
while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
{
sec = &sectors[secnum];
if (sec->specialdata)
continue;
// new door thinker
rtn = 1;
ceiling = Z_Malloc (sizeof(*ceiling), PU_LEVSPEC, 0);
P_AddThinker (&ceiling->thinker);
sec->specialdata = ceiling;
ceiling->thinker.function.acp1 = (actionf_p1)T_MoveCeiling;
ceiling->sector = sec;
ceiling->crush = false;
switch(type)
{
case fastCrushAndRaise:
ceiling->crush = true;
ceiling->topheight = sec->ceilingheight;
ceiling->bottomheight = sec->floorheight + (8*FRACUNIT);
ceiling->direction = -1;
ceiling->speed = CEILSPEED * 2;
break;
case silentCrushAndRaise:
case crushAndRaise:
ceiling->crush = true;
ceiling->topheight = sec->ceilingheight;
// fall through
case lowerAndCrush:
case lowerToFloor:
ceiling->bottomheight = sec->floorheight;
if (type != lowerToFloor)
ceiling->bottomheight += 8*FRACUNIT;
ceiling->direction = -1;
ceiling->speed = CEILSPEED;
break;
case raiseToHighest:
ceiling->topheight = P_FindHighestCeilingSurrounding(sec);
ceiling->direction = 1;
ceiling->speed = CEILSPEED;
break;
}
ceiling->tag = sec->tag;
ceiling->type = type;
P_AddActiveCeiling(ceiling);
}
return rtn;
}
//
// Add an active ceiling
//
void P_AddActiveCeiling(ceiling_t* c)
{
int i;
for (i = 0; i < MAXCEILINGS;i++)
{
if (activeceilings[i] == NULL)
{
activeceilings[i] = c;
return;
}
}
}
//
// Remove a ceiling's thinker
//
void P_RemoveActiveCeiling(ceiling_t* c)
{
int i;
for (i = 0;i < MAXCEILINGS;i++)
{
if (activeceilings[i] == c)
{
activeceilings[i]->sector->specialdata = NULL;
P_RemoveThinker (&activeceilings[i]->thinker);
activeceilings[i] = NULL;
break;
}
}
}
//
// Restart a ceiling that's in-stasis
//
void P_ActivateInStasisCeiling(line_t* line)
{
int i;
for (i = 0;i < MAXCEILINGS;i++)
{
if (activeceilings[i]
&& (activeceilings[i]->tag == line->tag)
&& (activeceilings[i]->direction == 0))
{
activeceilings[i]->direction = activeceilings[i]->olddirection;
activeceilings[i]->thinker.function.acp1
= (actionf_p1)T_MoveCeiling;
}
}
}
//
// EV_CeilingCrushStop
// Stop a ceiling from crushing!
//
int EV_CeilingCrushStop(line_t *line)
{
int i;
int rtn;
rtn = 0;
for (i = 0;i < MAXCEILINGS;i++)
{
if (activeceilings[i]
&& (activeceilings[i]->tag == line->tag)
&& (activeceilings[i]->direction != 0))
{
activeceilings[i]->olddirection = activeceilings[i]->direction;
activeceilings[i]->thinker.function.acv = (actionf_v)NULL;
activeceilings[i]->direction = 0; // in-stasis
rtn = 1;
}
}
return rtn;
}

546
apps/doom/p_doors.c Normal file
View File

@ -0,0 +1,546 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION: Door animation code (opening/closing)
//
#include "z_zone.h"
#include "doomdef.h"
#include "p_local.h"
#include "s_sound.h"
// State.
#include "doomstat.h"
#include "r_state.h"
// Data.
#include "dstrings.h"
#include "sounds.h"
//
// VERTICAL DOORS
//
//
// T_VerticalDoor
//
void T_VerticalDoor (vldoor_t* door)
{
result_e res;
switch(door->direction)
{
case 0:
// WAITING
if (!--door->topcountdown)
{
switch(door->type)
{
case vld_blazeRaise:
door->direction = -1; // time to go back down
S_StartSound(&door->sector->soundorg, sfx_bdcls);
break;
case vld_normal:
door->direction = -1; // time to go back down
S_StartSound(&door->sector->soundorg, sfx_dorcls);
break;
case vld_close30ThenOpen:
door->direction = 1;
S_StartSound(&door->sector->soundorg, sfx_doropn);
break;
default:
break;
}
}
break;
case 2:
// INITIAL WAIT
if (!--door->topcountdown)
{
switch(door->type)
{
case vld_raiseIn5Mins:
door->direction = 1;
door->type = vld_normal;
S_StartSound(&door->sector->soundorg, sfx_doropn);
break;
default:
break;
}
}
break;
case -1:
// DOWN
res = T_MovePlane(door->sector,
door->speed,
door->sector->floorheight,
false,1,door->direction);
if (res == pastdest)
{
switch(door->type)
{
case vld_blazeRaise:
case vld_blazeClose:
door->sector->specialdata = NULL;
P_RemoveThinker (&door->thinker); // unlink and free
S_StartSound(&door->sector->soundorg, sfx_bdcls);
break;
case vld_normal:
case vld_close:
door->sector->specialdata = NULL;
P_RemoveThinker (&door->thinker); // unlink and free
break;
case vld_close30ThenOpen:
door->direction = 0;
door->topcountdown = TICRATE*30;
break;
default:
break;
}
}
else if (res == crushed)
{
switch(door->type)
{
case vld_blazeClose:
case vld_close: // DO NOT GO BACK UP!
break;
default:
door->direction = 1;
S_StartSound(&door->sector->soundorg, sfx_doropn);
break;
}
}
break;
case 1:
// UP
res = T_MovePlane(door->sector,
door->speed,
door->topheight,
false,1,door->direction);
if (res == pastdest)
{
switch(door->type)
{
case vld_blazeRaise:
case vld_normal:
door->direction = 0; // wait at top
door->topcountdown = door->topwait;
break;
case vld_close30ThenOpen:
case vld_blazeOpen:
case vld_open:
door->sector->specialdata = NULL;
P_RemoveThinker (&door->thinker); // unlink and free
break;
default:
break;
}
}
break;
}
}
//
// EV_DoLockedDoor
// Move a locked door up/down
//
int
EV_DoLockedDoor
( line_t* line,
vldoor_e type,
mobj_t* thing )
{
player_t* p;
p = thing->player;
if (!p)
return 0;
switch(line->special)
{
case 99: // Blue Lock
case 133:
if ( !p )
return 0;
if (!p->cards[it_bluecard] && !p->cards[it_blueskull])
{
p->message = PD_BLUEO;
S_StartSound(NULL,sfx_oof);
return 0;
}
break;
case 134: // Red Lock
case 135:
if ( !p )
return 0;
if (!p->cards[it_redcard] && !p->cards[it_redskull])
{
p->message = PD_REDO;
S_StartSound(NULL,sfx_oof);
return 0;
}
break;
case 136: // Yellow Lock
case 137:
if ( !p )
return 0;
if (!p->cards[it_yellowcard] &&
!p->cards[it_yellowskull])
{
p->message = PD_YELLOWO;
S_StartSound(NULL,sfx_oof);
return 0;
}
break;
}
return EV_DoDoor(line,type);
}
int
EV_DoDoor
( line_t* line,
vldoor_e type )
{
int secnum,rtn;
sector_t* sec;
vldoor_t* door;
secnum = -1;
rtn = 0;
while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
{
sec = &sectors[secnum];
if (sec->specialdata)
continue;
// new door thinker
rtn = 1;
door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0);
P_AddThinker (&door->thinker);
sec->specialdata = door;
door->thinker.function.acp1 = (actionf_p1) T_VerticalDoor;
door->sector = sec;
door->type = type;
door->topwait = VDOORWAIT;
door->speed = VDOORSPEED;
switch(type)
{
case vld_blazeClose:
door->topheight = P_FindLowestCeilingSurrounding(sec);
door->topheight -= 4*FRACUNIT;
door->direction = -1;
door->speed = VDOORSPEED * 4;
S_StartSound(&door->sector->soundorg, sfx_bdcls);
break;
case vld_close:
door->topheight = P_FindLowestCeilingSurrounding(sec);
door->topheight -= 4*FRACUNIT;
door->direction = -1;
S_StartSound(&door->sector->soundorg, sfx_dorcls);
break;
case vld_close30ThenOpen:
door->topheight = sec->ceilingheight;
door->direction = -1;
S_StartSound(&door->sector->soundorg, sfx_dorcls);
break;
case vld_blazeRaise:
case vld_blazeOpen:
door->direction = 1;
door->topheight = P_FindLowestCeilingSurrounding(sec);
door->topheight -= 4*FRACUNIT;
door->speed = VDOORSPEED * 4;
if (door->topheight != sec->ceilingheight)
S_StartSound(&door->sector->soundorg, sfx_bdopn);
break;
case vld_normal:
case vld_open:
door->direction = 1;
door->topheight = P_FindLowestCeilingSurrounding(sec);
door->topheight -= 4*FRACUNIT;
if (door->topheight != sec->ceilingheight)
S_StartSound(&door->sector->soundorg, sfx_doropn);
break;
default:
break;
}
}
return rtn;
}
//
// EV_VerticalDoor : open a door manually, no tag value
//
void
EV_VerticalDoor
( line_t* line,
mobj_t* thing )
{
player_t* player;
sector_t* sec;
vldoor_t* door;
int side;
side = 0; // only front sides can be used
// Check for locks
player = thing->player;
switch(line->special)
{
case 26: // Blue Lock
case 32:
if ( !player )
return;
if (!player->cards[it_bluecard] && !player->cards[it_blueskull])
{
player->message = PD_BLUEK;
S_StartSound(NULL,sfx_oof);
return;
}
break;
case 27: // Yellow Lock
case 34:
if ( !player )
return;
if (!player->cards[it_yellowcard] &&
!player->cards[it_yellowskull])
{
player->message = PD_YELLOWK;
S_StartSound(NULL,sfx_oof);
return;
}
break;
case 28: // Red Lock
case 33:
if ( !player )
return;
if (!player->cards[it_redcard] && !player->cards[it_redskull])
{
player->message = PD_REDK;
S_StartSound(NULL,sfx_oof);
return;
}
break;
}
// if the sector has an active thinker, use it
sec = sides[ line->sidenum[side^1]] .sector;
if (sec->specialdata)
{
door = sec->specialdata;
switch(line->special)
{
case 1: // ONLY FOR "RAISE" DOORS, NOT "OPEN"s
case 26:
case 27:
case 28:
case 117:
if (door->direction == -1)
door->direction = 1; // go back up
else
{
if (!thing->player)
return; // JDC: bad guys never close doors
// When is a door not a door?
// In Vanilla, door->direction is set, even though
// "specialdata" might not actually point at a door.
if (door->thinker.function.acp1 == (actionf_p1) T_VerticalDoor)
{
door->direction = -1; // start going down immediately
}
else if (door->thinker.function.acp1 == (actionf_p1) T_PlatRaise)
{
// Erm, this is a plat, not a door.
// This notably causes a problem in ep1-0500.lmp where
// a plat and a door are cross-referenced; the door
// doesn't open on 64-bit.
// The direction field in vldoor_t corresponds to the wait
// field in plat_t. Let's set that to -1 instead.
plat_t *plat;
plat = (plat_t *) door;
plat->wait = -1;
}
else
{
// This isn't a door OR a plat. Now we're in trouble.
ES_debugf("EV_VerticalDoor: Tried to close "
"something that wasn't a door.\n");
// Try closing it anyway. At least it will work on 32-bit
// machines.
door->direction = -1;
}
}
return;
}
}
// for proper sound
switch(line->special)
{
case 117: // BLAZING DOOR RAISE
case 118: // BLAZING DOOR OPEN
S_StartSound(&sec->soundorg,sfx_bdopn);
break;
case 1: // NORMAL DOOR SOUND
case 31:
S_StartSound(&sec->soundorg,sfx_doropn);
break;
default: // LOCKED DOOR SOUND
S_StartSound(&sec->soundorg,sfx_doropn);
break;
}
// new door thinker
door = Z_Malloc (sizeof(*door), PU_LEVSPEC, 0);
P_AddThinker (&door->thinker);
sec->specialdata = door;
door->thinker.function.acp1 = (actionf_p1) T_VerticalDoor;
door->sector = sec;
door->direction = 1;
door->speed = VDOORSPEED;
door->topwait = VDOORWAIT;
switch(line->special)
{
case 1:
case 26:
case 27:
case 28:
door->type = vld_normal;
break;
case 31:
case 32:
case 33:
case 34:
door->type = vld_open;
line->special = 0;
break;
case 117: // blazing door raise
door->type = vld_blazeRaise;
door->speed = VDOORSPEED*4;
break;
case 118: // blazing door open
door->type = vld_blazeOpen;
line->special = 0;
door->speed = VDOORSPEED*4;
break;
}
// find the top and bottom of the movement range
door->topheight = P_FindLowestCeilingSurrounding(sec);
door->topheight -= 4*FRACUNIT;
}
//
// Spawn a door that closes after 30 seconds
//
void P_SpawnDoorCloseIn30 (sector_t* sec)
{
vldoor_t* door;
door = Z_Malloc ( sizeof(*door), PU_LEVSPEC, 0);
P_AddThinker (&door->thinker);
sec->specialdata = door;
sec->special = 0;
door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
door->sector = sec;
door->direction = 0;
door->type = vld_normal;
door->speed = VDOORSPEED;
door->topcountdown = 30 * TICRATE;
}
//
// Spawn a door that opens after 5 minutes
//
void
P_SpawnDoorRaiseIn5Mins
( sector_t* sec,
int secnum )
{
vldoor_t* door;
door = Z_Malloc ( sizeof(*door), PU_LEVSPEC, 0);
P_AddThinker (&door->thinker);
sec->specialdata = door;
sec->special = 0;
door->thinker.function.acp1 = (actionf_p1)T_VerticalDoor;
door->sector = sec;
door->direction = 2;
door->type = vld_raiseIn5Mins;
door->speed = VDOORSPEED;
door->topheight = P_FindLowestCeilingSurrounding(sec);
door->topheight -= 4*FRACUNIT;
door->topwait = VDOORWAIT;
door->topcountdown = 5 * 60 * TICRATE;
}

2002
apps/doom/p_enemy.c Normal file

File diff suppressed because it is too large Load Diff

547
apps/doom/p_floor.c Normal file
View File

@ -0,0 +1,547 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Floor animation: raising stairs.
//
#include "z_zone.h"
#include "doomdef.h"
#include "p_local.h"
#include "s_sound.h"
// State.
#include "doomstat.h"
#include "r_state.h"
// Data.
#include "sounds.h"
//
// FLOORS
//
//
// Move a plane (floor or ceiling) and check for crushing
//
result_e
T_MovePlane
( sector_t* sector,
fixed_t speed,
fixed_t dest,
boolean crush,
int floorOrCeiling,
int direction )
{
boolean flag;
fixed_t lastpos;
switch(floorOrCeiling)
{
case 0:
// FLOOR
switch(direction)
{
case -1:
// DOWN
if (sector->floorheight - speed < dest)
{
lastpos = sector->floorheight;
sector->floorheight = dest;
flag = P_ChangeSector(sector,crush);
if (flag == true)
{
sector->floorheight =lastpos;
P_ChangeSector(sector,crush);
//return crushed;
}
return pastdest;
}
else
{
lastpos = sector->floorheight;
sector->floorheight -= speed;
flag = P_ChangeSector(sector,crush);
if (flag == true)
{
sector->floorheight = lastpos;
P_ChangeSector(sector,crush);
return crushed;
}
}
break;
case 1:
// UP
if (sector->floorheight + speed > dest)
{
lastpos = sector->floorheight;
sector->floorheight = dest;
flag = P_ChangeSector(sector,crush);
if (flag == true)
{
sector->floorheight = lastpos;
P_ChangeSector(sector,crush);
//return crushed;
}
return pastdest;
}
else
{
// COULD GET CRUSHED
lastpos = sector->floorheight;
sector->floorheight += speed;
flag = P_ChangeSector(sector,crush);
if (flag == true)
{
if (crush == true)
return crushed;
sector->floorheight = lastpos;
P_ChangeSector(sector,crush);
return crushed;
}
}
break;
}
break;
case 1:
// CEILING
switch(direction)
{
case -1:
// DOWN
if (sector->ceilingheight - speed < dest)
{
lastpos = sector->ceilingheight;
sector->ceilingheight = dest;
flag = P_ChangeSector(sector,crush);
if (flag == true)
{
sector->ceilingheight = lastpos;
P_ChangeSector(sector,crush);
//return crushed;
}
return pastdest;
}
else
{
// COULD GET CRUSHED
lastpos = sector->ceilingheight;
sector->ceilingheight -= speed;
flag = P_ChangeSector(sector,crush);
if (flag == true)
{
if (crush == true)
return crushed;
sector->ceilingheight = lastpos;
P_ChangeSector(sector,crush);
return crushed;
}
}
break;
case 1:
// UP
if (sector->ceilingheight + speed > dest)
{
lastpos = sector->ceilingheight;
sector->ceilingheight = dest;
flag = P_ChangeSector(sector,crush);
if (flag == true)
{
sector->ceilingheight = lastpos;
P_ChangeSector(sector,crush);
//return crushed;
}
return pastdest;
}
else
{
lastpos = sector->ceilingheight;
sector->ceilingheight += speed;
flag = P_ChangeSector(sector,crush);
// UNUSED
#if 0
if (flag == true)
{
sector->ceilingheight = lastpos;
P_ChangeSector(sector,crush);
return crushed;
}
#endif
}
break;
}
break;
}
return ok;
}
//
// MOVE A FLOOR TO IT'S DESTINATION (UP OR DOWN)
//
void T_MoveFloor(floormove_t* floor)
{
result_e res;
res = T_MovePlane(floor->sector,
floor->speed,
floor->floordestheight,
floor->crush,0,floor->direction);
if (!(leveltime&7))
S_StartSound(&floor->sector->soundorg, sfx_stnmov);
if (res == pastdest)
{
floor->sector->specialdata = NULL;
if (floor->direction == 1)
{
switch(floor->type)
{
case donutRaise:
floor->sector->special = floor->newspecial;
floor->sector->floorpic = floor->texture;
default:
break;
}
}
else if (floor->direction == -1)
{
switch(floor->type)
{
case lowerAndChange:
floor->sector->special = floor->newspecial;
floor->sector->floorpic = floor->texture;
default:
break;
}
}
P_RemoveThinker(&floor->thinker);
S_StartSound(&floor->sector->soundorg, sfx_pstop);
}
}
//
// HANDLE FLOOR TYPES
//
int
EV_DoFloor
( line_t* line,
floor_e floortype )
{
int secnum;
int rtn;
int i;
sector_t* sec;
floormove_t* floor;
secnum = -1;
rtn = 0;
while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
{
sec = &sectors[secnum];
// ALREADY MOVING? IF SO, KEEP GOING...
if (sec->specialdata)
continue;
// new floor thinker
rtn = 1;
floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
P_AddThinker (&floor->thinker);
sec->specialdata = floor;
floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor;
floor->type = floortype;
floor->crush = false;
switch(floortype)
{
case lowerFloor:
floor->direction = -1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight =
P_FindHighestFloorSurrounding(sec);
break;
case lowerFloorToLowest:
floor->direction = -1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight =
P_FindLowestFloorSurrounding(sec);
break;
case turboLower:
floor->direction = -1;
floor->sector = sec;
floor->speed = FLOORSPEED * 4;
floor->floordestheight =
P_FindHighestFloorSurrounding(sec);
if (floor->floordestheight != sec->floorheight)
floor->floordestheight += 8*FRACUNIT;
break;
case raiseFloorCrush:
floor->crush = true;
// fall through
case raiseFloor:
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight =
P_FindLowestCeilingSurrounding(sec);
if (floor->floordestheight > sec->ceilingheight)
floor->floordestheight = sec->ceilingheight;
floor->floordestheight -= (8*FRACUNIT)*
(floortype == raiseFloorCrush);
break;
case raiseFloorTurbo:
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED*4;
floor->floordestheight =
P_FindNextHighestFloor(sec,sec->floorheight);
break;
case raiseFloorToNearest:
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight =
P_FindNextHighestFloor(sec,sec->floorheight);
break;
case raiseFloor24:
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight = floor->sector->floorheight +
24 * FRACUNIT;
break;
case raiseFloor512:
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight = floor->sector->floorheight +
512 * FRACUNIT;
break;
case raiseFloor24AndChange:
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight = floor->sector->floorheight +
24 * FRACUNIT;
sec->floorpic = line->frontsector->floorpic;
sec->special = line->frontsector->special;
break;
case raiseToTexture:
{
int minsize = INT_MAX;
side_t* side;
floor->direction = 1;
floor->sector = sec;
floor->speed = FLOORSPEED;
for (i = 0; i < sec->linecount; i++)
{
if (twoSided (secnum, i) )
{
side = getSide(secnum,i,0);
if (side->bottomtexture >= 0)
if (textureheight[side->bottomtexture] <
minsize)
minsize =
textureheight[side->bottomtexture];
side = getSide(secnum,i,1);
if (side->bottomtexture >= 0)
if (textureheight[side->bottomtexture] <
minsize)
minsize =
textureheight[side->bottomtexture];
}
}
floor->floordestheight =
floor->sector->floorheight + minsize;
}
break;
case lowerAndChange:
floor->direction = -1;
floor->sector = sec;
floor->speed = FLOORSPEED;
floor->floordestheight =
P_FindLowestFloorSurrounding(sec);
floor->texture = sec->floorpic;
for (i = 0; i < sec->linecount; i++)
{
if ( twoSided(secnum, i) )
{
if (getSide(secnum,i,0)->sector-sectors == secnum)
{
sec = getSector(secnum,i,1);
if (sec->floorheight == floor->floordestheight)
{
floor->texture = sec->floorpic;
floor->newspecial = sec->special;
break;
}
}
else
{
sec = getSector(secnum,i,0);
if (sec->floorheight == floor->floordestheight)
{
floor->texture = sec->floorpic;
floor->newspecial = sec->special;
break;
}
}
}
}
default:
break;
}
}
return rtn;
}
//
// BUILD A STAIRCASE!
//
int
EV_BuildStairs
( line_t* line,
stair_e type )
{
int secnum;
int height;
int i;
int newsecnum;
int texture;
int ok;
int rtn;
sector_t* sec;
sector_t* tsec;
floormove_t* floor;
fixed_t stairsize = 0;
fixed_t speed = 0;
secnum = -1;
rtn = 0;
while ((secnum = P_FindSectorFromLineTag(line,secnum)) >= 0)
{
sec = &sectors[secnum];
// ALREADY MOVING? IF SO, KEEP GOING...
if (sec->specialdata)
continue;
// new floor thinker
rtn = 1;
floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
P_AddThinker (&floor->thinker);
sec->specialdata = floor;
floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor;
floor->direction = 1;
floor->sector = sec;
switch(type)
{
case build8:
speed = FLOORSPEED/4;
stairsize = 8*FRACUNIT;
break;
case turbo16:
speed = FLOORSPEED*4;
stairsize = 16*FRACUNIT;
break;
}
floor->speed = speed;
height = sec->floorheight + stairsize;
floor->floordestheight = height;
texture = sec->floorpic;
// Find next sector to raise
// 1. Find 2-sided line with same sector side[0]
// 2. Other side is the next sector to raise
do
{
ok = 0;
for (i = 0;i < sec->linecount;i++)
{
if ( !((sec->lines[i])->flags & ML_TWOSIDED) )
continue;
tsec = (sec->lines[i])->frontsector;
newsecnum = tsec-sectors;
if (secnum != newsecnum)
continue;
tsec = (sec->lines[i])->backsector;
newsecnum = tsec - sectors;
if (tsec->floorpic != texture)
continue;
height += stairsize;
if (tsec->specialdata)
continue;
sec = tsec;
secnum = newsecnum;
floor = Z_Malloc (sizeof(*floor), PU_LEVSPEC, 0);
P_AddThinker (&floor->thinker);
sec->specialdata = floor;
floor->thinker.function.acp1 = (actionf_p1) T_MoveFloor;
floor->direction = 1;
floor->sector = sec;
floor->speed = speed;
floor->floordestheight = height;
ok = 1;
break;
}
} while(ok);
}
return rtn;
}

916
apps/doom/p_inter.c Normal file
View File

@ -0,0 +1,916 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Handling interactions (i.e., collisions).
//
#include "config.h"
#include "doomdef.h"
#include "dstrings.h"
#include "sounds.h"
#include "doomstat.h"
#include "m_random.h"
#include "i_system.h"
#include "am_map.h"
#include "p_local.h"
#include "s_sound.h"
#include "p_inter.h"
#define BONUSADD 6
// a weapon is found with two clip loads,
// a big item has five clip loads
int maxammo[NUMAMMO] = {200, 50, 300, 50};
int clipammo[NUMAMMO] = {10, 4, 20, 1};
//
// GET STUFF
//
//
// P_GiveAmmo
// Num is the number of clip loads,
// not the individual count (0= 1/2 clip).
// Returns false if the ammo can't be picked up at all
//
boolean
P_GiveAmmo
( player_t* player,
ammotype_t ammo,
int num )
{
int oldammo;
if (ammo == am_noammo)
return false;
if (ammo > NUMAMMO)
I_Error ("P_GiveAmmo: bad type %i", ammo);
if ( player->ammo[ammo] == player->maxammo[ammo] )
return false;
if (num)
num *= clipammo[ammo];
else
num = clipammo[ammo]/2;
if (gameskill == sk_baby
|| gameskill == sk_nightmare)
{
// give double ammo in trainer mode,
// you'll need in nightmare
num <<= 1;
}
oldammo = player->ammo[ammo];
player->ammo[ammo] += num;
if (player->ammo[ammo] > player->maxammo[ammo])
player->ammo[ammo] = player->maxammo[ammo];
// If non zero ammo,
// don't change up weapons,
// player was lower on purpose.
if (oldammo)
return true;
// We were down to zero,
// so select a new weapon.
// Preferences are not user selectable.
switch (ammo)
{
case am_clip:
if (player->readyweapon == wp_fist)
{
if (player->weaponowned[wp_chaingun])
player->pendingweapon = wp_chaingun;
else
player->pendingweapon = wp_pistol;
}
break;
case am_shell:
if (player->readyweapon == wp_fist
|| player->readyweapon == wp_pistol)
{
if (player->weaponowned[wp_shotgun])
player->pendingweapon = wp_shotgun;
}
break;
case am_cell:
if (player->readyweapon == wp_fist
|| player->readyweapon == wp_pistol)
{
if (player->weaponowned[wp_plasma])
player->pendingweapon = wp_plasma;
}
break;
case am_misl:
if (player->readyweapon == wp_fist)
{
if (player->weaponowned[wp_missile])
player->pendingweapon = wp_missile;
}
default:
break;
}
return true;
}
//
// P_GiveWeapon
// The weapon name may have a MF_DROPPED flag ored in.
//
boolean
P_GiveWeapon
( player_t* player,
weapontype_t weapon,
boolean dropped )
{
boolean gaveammo;
boolean gaveweapon;
if (netgame && (deathmatch!=2) && !dropped )
{
// leave placed weapons forever on net games
if (player->weaponowned[weapon])
return false;
player->bonuscount += BONUSADD;
player->weaponowned[weapon] = true;
if (deathmatch)
P_GiveAmmo (player, weaponinfo[weapon].ammo, 5);
else
P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
player->pendingweapon = weapon;
if (player == &players[consoleplayer])
S_StartSound (NULL, sfx_wpnup);
return false;
}
if (weaponinfo[weapon].ammo != am_noammo)
{
// give one clip with a dropped weapon,
// two clips with a found weapon
if (dropped)
gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 1);
else
gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
}
else
{
gaveammo = false;
}
if (player->weaponowned[weapon])
{
gaveweapon = false;
}
else
{
gaveweapon = true;
player->weaponowned[weapon] = true;
player->pendingweapon = weapon;
}
return (gaveweapon || gaveammo);
}
//
// P_GiveBody
// Returns false if the body isn't needed at all
//
boolean
P_GiveBody
( player_t* player,
int num )
{
if (player->health >= MAXHEALTH)
return false;
player->health += num;
if (player->health > MAXHEALTH)
player->health = MAXHEALTH;
player->mo->health = player->health;
return true;
}
//
// P_GiveArmor
// Returns false if the armor is worse
// than the current armor.
//
boolean
P_GiveArmor
( player_t* player,
int armortype )
{
int hits;
hits = armortype*100;
if (player->armorpoints >= hits)
return false; // don't pick up
player->armortype = armortype;
player->armorpoints = hits;
return true;
}
//
// P_GiveCard
//
void
P_GiveCard
( player_t* player,
card_t card )
{
if (player->cards[card])
return;
player->bonuscount = BONUSADD;
player->cards[card] = 1;
}
//
// P_GivePower
//
boolean
P_GivePower
( player_t* player,
int /*powertype_t*/ power )
{
if (power == pw_invulnerability)
{
player->powers[power] = INVULNTICS;
return true;
}
if (power == pw_invisibility)
{
player->powers[power] = INVISTICS;
player->mo->flags |= MF_SHADOW;
return true;
}
if (power == pw_infrared)
{
player->powers[power] = INFRATICS;
return true;
}
if (power == pw_ironfeet)
{
player->powers[power] = IRONTICS;
return true;
}
if (power == pw_strength)
{
P_GiveBody (player, 100);
player->powers[power] = 1;
return true;
}
if (player->powers[power])
return false; // already got it
player->powers[power] = 1;
return true;
}
//
// P_TouchSpecialThing
//
void
P_TouchSpecialThing
( mobj_t* special,
mobj_t* toucher )
{
player_t* player;
int i;
fixed_t delta;
int sound;
delta = special->z - toucher->z;
if (delta > toucher->height
|| delta < -8*FRACUNIT)
{
// out of reach
return;
}
sound = sfx_itemup;
player = toucher->player;
// Dead thing touching.
// Can happen with a sliding player corpse.
if (toucher->health <= 0)
return;
// Identify by sprite.
switch (special->sprite)
{
// armor
case SPR_ARM1:
if (!P_GiveArmor (player, GREEN_ARMOR_CLASS))
return;
player->message = GOTARMOR;
break;
case SPR_ARM2:
if (!P_GiveArmor (player, BLUE_ARMOR_CLASS))
return;
player->message = GOTMEGA;
break;
// bonus items
case SPR_BON1:
player->health++; // can go over 100%
if (player->health > MAX_HEALTH)
player->health = MAX_HEALTH;
player->mo->health = player->health;
player->message = GOTHTHBONUS;
break;
case SPR_BON2:
player->armorpoints++; // can go over 100%
if (player->armorpoints > MAX_ARMOR)
player->armorpoints = MAX_ARMOR;
if (!player->armortype)
player->armortype = 1;
player->message = GOTARMBONUS;
break;
case SPR_SOUL:
player->health += SOULSPHERE_HEALTH;
if (player->health > MAX_SOULSPHERE)
player->health = MAX_SOULSPHERE;
player->mo->health = player->health;
player->message = GOTSUPER;
sound = sfx_getpow;
break;
case SPR_MEGA:
if (gamemode != commercial)
return;
player->health = MEGASPHERE_HEALTH;
player->mo->health = player->health;
// We always give armor type 2 for the megasphere; dehacked only
// affects the MegaArmor.
P_GiveArmor (player, 2);
player->message = GOTMSPHERE;
sound = sfx_getpow;
break;
// cards
// leave cards for everyone
case SPR_BKEY:
if (!player->cards[it_bluecard])
player->message = GOTBLUECARD;
P_GiveCard (player, it_bluecard);
if (!netgame)
break;
return;
case SPR_YKEY:
if (!player->cards[it_yellowcard])
player->message = GOTYELWCARD;
P_GiveCard (player, it_yellowcard);
if (!netgame)
break;
return;
case SPR_RKEY:
if (!player->cards[it_redcard])
player->message = GOTREDCARD;
P_GiveCard (player, it_redcard);
if (!netgame)
break;
return;
case SPR_BSKU:
if (!player->cards[it_blueskull])
player->message = GOTBLUESKUL;
P_GiveCard (player, it_blueskull);
if (!netgame)
break;
return;
case SPR_YSKU:
if (!player->cards[it_yellowskull])
player->message = GOTYELWSKUL;
P_GiveCard (player, it_yellowskull);
if (!netgame)
break;
return;
case SPR_RSKU:
if (!player->cards[it_redskull])
player->message = GOTREDSKULL;
P_GiveCard (player, it_redskull);
if (!netgame)
break;
return;
// medikits, heals
case SPR_STIM:
if (!P_GiveBody (player, 10))
return;
player->message = GOTSTIM;
break;
case SPR_MEDI:
if (!P_GiveBody (player, 25))
return;
if (player->health < 25)
player->message = GOTMEDINEED;
else
player->message = GOTMEDIKIT;
break;
// power ups
case SPR_PINV:
if (!P_GivePower (player, pw_invulnerability))
return;
player->message = GOTINVUL;
sound = sfx_getpow;
break;
case SPR_PSTR:
if (!P_GivePower (player, pw_strength))
return;
player->message = GOTBERSERK;
if (player->readyweapon != wp_fist)
player->pendingweapon = wp_fist;
sound = sfx_getpow;
break;
case SPR_PINS:
if (!P_GivePower (player, pw_invisibility))
return;
player->message = GOTINVIS;
sound = sfx_getpow;
break;
case SPR_SUIT:
if (!P_GivePower (player, pw_ironfeet))
return;
player->message = GOTSUIT;
sound = sfx_getpow;
break;
case SPR_PMAP:
if (!P_GivePower (player, pw_allmap))
return;
player->message = GOTMAP;
sound = sfx_getpow;
break;
case SPR_PVIS:
if (!P_GivePower (player, pw_infrared))
return;
player->message = GOTVISOR;
sound = sfx_getpow;
break;
// ammo
case SPR_CLIP:
if (special->flags & MF_DROPPED)
{
if (!P_GiveAmmo (player,am_clip,0))
return;
}
else
{
if (!P_GiveAmmo (player,am_clip,1))
return;
}
player->message = GOTCLIP;
break;
case SPR_AMMO:
if (!P_GiveAmmo (player, am_clip,5))
return;
player->message = GOTCLIPBOX;
break;
case SPR_ROCK:
if (!P_GiveAmmo (player, am_misl,1))
return;
player->message = GOTROCKET;
break;
case SPR_BROK:
if (!P_GiveAmmo (player, am_misl,5))
return;
player->message = GOTROCKBOX;
break;
case SPR_CELL:
if (!P_GiveAmmo (player, am_cell,1))
return;
player->message = GOTCELL;
break;
case SPR_CELP:
if (!P_GiveAmmo (player, am_cell,5))
return;
player->message = GOTCELLBOX;
break;
case SPR_SHEL:
if (!P_GiveAmmo (player, am_shell,1))
return;
player->message = GOTSHELLS;
break;
case SPR_SBOX:
if (!P_GiveAmmo (player, am_shell,5))
return;
player->message = GOTSHELLBOX;
break;
case SPR_BPAK:
if (!player->backpack)
{
for (i=0 ; i<NUMAMMO ; i++)
player->maxammo[i] *= 2;
player->backpack = true;
}
for (i=0 ; i<NUMAMMO ; i++)
P_GiveAmmo (player, i, 1);
player->message = GOTBACKPACK;
break;
// weapons
case SPR_BFUG:
if (!P_GiveWeapon (player, wp_bfg, false) )
return;
player->message = GOTBFG9000;
sound = sfx_wpnup;
break;
case SPR_MGUN:
if (!P_GiveWeapon (player, wp_chaingun, (special->flags&MF_DROPPED) != 0) )
return;
player->message = GOTCHAINGUN;
sound = sfx_wpnup;
break;
case SPR_CSAW:
if (!P_GiveWeapon (player, wp_chainsaw, false) )
return;
player->message = GOTCHAINSAW;
sound = sfx_wpnup;
break;
case SPR_LAUN:
if (!P_GiveWeapon (player, wp_missile, false) )
return;
player->message = GOTLAUNCHER;
sound = sfx_wpnup;
break;
case SPR_PLAS:
if (!P_GiveWeapon (player, wp_plasma, false) )
return;
player->message = GOTPLASMA;
sound = sfx_wpnup;
break;
case SPR_SHOT:
if (!P_GiveWeapon (player, wp_shotgun, (special->flags&MF_DROPPED) != 0 ) )
return;
player->message = GOTSHOTGUN;
sound = sfx_wpnup;
break;
case SPR_SGN2:
if (!P_GiveWeapon (player, wp_supershotgun, (special->flags&MF_DROPPED) != 0 ) )
return;
player->message = GOTSHOTGUN2;
sound = sfx_wpnup;
break;
default:
I_Error ("P_SpecialThing: Unknown gettable thing");
}
if (special->flags & MF_COUNTITEM)
player->itemcount++;
P_RemoveMobj (special);
player->bonuscount += BONUSADD;
if (player == &players[consoleplayer])
S_StartSound (NULL, sound);
}
//
// KillMobj
//
void
P_KillMobj
( mobj_t* source,
mobj_t* target )
{
mobjtype_t item;
mobj_t* mo;
target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY);
if (target->type != MT_SKULL)
target->flags &= ~MF_NOGRAVITY;
target->flags |= MF_CORPSE|MF_DROPOFF;
target->height >>= 2;
if (source && source->player)
{
// count for intermission
if (target->flags & MF_COUNTKILL)
source->player->killcount++;
if (target->player)
source->player->frags[target->player-players]++;
}
else if (!netgame && (target->flags & MF_COUNTKILL) )
{
// count all monster deaths,
// even those caused by other monsters
players[0].killcount++;
}
if (target->player)
{
// count environment kills against you
if (!source)
target->player->frags[target->player-players]++;
target->flags &= ~MF_SOLID;
target->player->playerstate = PST_DEAD;
P_DropWeapon (target->player);
if (target->player == &players[consoleplayer]
&& automapactive)
{
// don't die in auto map,
// switch view prior to dying
AM_Stop ();
}
}
if (target->health < -target->info->spawnhealth
&& target->info->xdeathstate)
{
P_SetMobjState (target, target->info->xdeathstate);
}
else
P_SetMobjState (target, target->info->deathstate);
target->tics -= P_Random()&3;
if (target->tics < 1)
target->tics = 1;
// I_StartSound (&actor->r, actor->info->deathsound);
// In Chex Quest, monsters don't drop items.
if (gameversion == exe_chex)
{
return;
}
// Drop stuff.
// This determines the kind of object spawned
// during the death frame of a thing.
switch (target->type)
{
case MT_WOLFSS:
case MT_POSSESSED:
item = MT_CLIP;
break;
case MT_SHOTGUY:
item = MT_SHOTGUN;
break;
case MT_CHAINGUY:
item = MT_CHAINGUN;
break;
default:
return;
}
mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item);
mo->flags |= MF_DROPPED; // special versions of items
}
//
// P_DamageMobj
// Damages both enemies and players
// "inflictor" is the thing that caused the damage
// creature or missile, can be NULL (slime, etc)
// "source" is the thing to target after taking damage
// creature or NULL
// Source and inflictor are the same for melee attacks.
// Source can be NULL for slime, barrel explosions
// and other environmental stuff.
//
void
P_DamageMobj
( mobj_t* target,
mobj_t* inflictor,
mobj_t* source,
int damage )
{
unsigned ang;
int saved;
player_t* player;
fixed_t thrust;
int temp;
if ( !(target->flags & MF_SHOOTABLE) )
return; // shouldn't happen...
if (target->health <= 0)
return;
if ( target->flags & MF_SKULLFLY )
{
target->momx = target->momy = target->momz = 0;
}
player = target->player;
if (player && gameskill == sk_baby)
damage >>= 1; // take half damage in trainer mode
// Some close combat weapons should not
// inflict thrust and push the victim out of reach,
// thus kick away unless using the chainsaw.
if (inflictor
&& !(target->flags & MF_NOCLIP)
&& (!source
|| !source->player
|| source->player->readyweapon != wp_chainsaw))
{
ang = R_PointToAngle2 ( inflictor->x,
inflictor->y,
target->x,
target->y);
thrust = damage*(FRACUNIT>>3)*100/target->info->mass;
// make fall forwards sometimes
if ( damage < 40
&& damage > target->health
&& target->z - inflictor->z > 64*FRACUNIT
&& (P_Random ()&1) )
{
ang += ANG180;
thrust *= 4;
}
ang >>= ANGLETOFINESHIFT;
target->momx += FixedMul (thrust, finecosine[ang]);
target->momy += FixedMul (thrust, finesine[ang]);
}
// player specific
if (player)
{
// end of game hell hack
if (target->subsector->sector->special == 11
&& damage >= target->health)
{
damage = target->health - 1;
}
// Below certain threshold,
// ignore damage in GOD mode, or with INVUL power.
if ( damage < 1000
&& ( (player->cheats&CF_GODMODE)
|| player->powers[pw_invulnerability] ) )
{
return;
}
if (player->armortype)
{
if (player->armortype == 1)
saved = damage/3;
else
saved = damage/2;
if (player->armorpoints <= saved)
{
// armor is used up
saved = player->armorpoints;
player->armortype = 0;
}
player->armorpoints -= saved;
damage -= saved;
}
player->health -= damage; // mirror mobj health here for Dave
if (player->health < 0)
player->health = 0;
player->attacker = source;
player->damagecount += damage; // add damage after armor / invuln
if (player->damagecount > 100)
player->damagecount = 100; // teleport stomp does 10k points...
temp = damage < 100 ? damage : 100;
if (player == &players[consoleplayer])
I_Tactile (40,10,40+temp*2);
}
// do the damage
target->health -= damage;
if (target->health <= 0)
{
P_KillMobj (source, target);
return;
}
if ( (P_Random () < target->info->painchance)
&& !(target->flags&MF_SKULLFLY) )
{
target->flags |= MF_JUSTHIT; // fight back!
P_SetMobjState (target, target->info->painstate);
}
target->reactiontime = 0; // we're awake now...
if ( (!target->threshold || target->type == MT_VILE)
&& source && source != target
&& source->type != MT_VILE)
{
// if not intent on another player,
// chase after this one
target->target = source;
target->threshold = BASETHRESHOLD;
if (target->state == &states[target->info->spawnstate]
&& target->info->seestate != S_NULL)
P_SetMobjState (target, target->info->seestate);
}
}

30
apps/doom/p_inter.h Normal file
View File

@ -0,0 +1,30 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
//
//
#ifndef __P_INTER__
#define __P_INTER__
boolean P_GivePower(player_t*, int);
#endif

Some files were not shown because too many files have changed in this diff Show More