diff --git a/src/am_map.cpp b/src/am_map.cpp index 11ecf74a..44b6da61 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -308,6 +308,7 @@ struct islope_t static TArray MapArrow; static TArray CheatMapArrow; static TArray CheatKey; +static TArray EasyKey; #define R (MAPUNIT) // [RH] Avoid lots of warnings without compiler-specific #pragmas @@ -536,10 +537,12 @@ void AM_StaticInit() MapArrow.Clear(); CheatMapArrow.Clear(); CheatKey.Clear(); + EasyKey.Clear(); if (gameinfo.mMapArrow.IsNotEmpty()) AM_ParseArrow(MapArrow, gameinfo.mMapArrow); if (gameinfo.mCheatMapArrow.IsNotEmpty()) AM_ParseArrow(CheatMapArrow, gameinfo.mCheatMapArrow); AM_ParseArrow(CheatKey, "maparrows/key.txt"); + AM_ParseArrow(EasyKey, "maparrows/ravenkey.txt"); if (MapArrow.Size() == 0) I_FatalError("No automap arrow defined"); char namebuf[9]; @@ -1917,13 +1920,13 @@ bool AM_Check3DFloors(line_t *line) //============================================================================= void AM_drawWalls (bool allmap) -{ - int i; - static mline_t l; - int lock, color; - - for (i = 0; i < numlines; i++) - { +{ + int i; + static mline_t l; + int lock, color; + + for (i = 0; i < numlines; i++) + { l.a.x = lines[i].v1->x >> FRACTOMAPBITS; l.a.y = lines[i].v1->y >> FRACTOMAPBITS; l.b.x = lines[i].v2->x >> FRACTOMAPBITS; @@ -1953,22 +1956,22 @@ void AM_drawWalls (bool allmap) else if (lines[i].flags & ML_SECRET) { // secret door if (am_cheat != 0 && lines[i].backsector != NULL) - AM_drawMline(&l, SecretWallColor); - else - AM_drawMline(&l, WallColor); - } else if (lines[i].locknumber > 0) { // [Dusk] specials w/ locknumbers - lock = lines[i].locknumber; - color = P_GetMapColorForLock(lock); - - AMColor c; - if (color >= 0) c.FromRGB(RPART(color), GPART(color), BPART(color)); - else c = LockedColor; - - AM_drawMline (&l, c); - } else if ((lines[i].special == Teleport || - lines[i].special == Teleport_NoFog || - lines[i].special == Teleport_ZombieChanger || - lines[i].special == Teleport_Line) && + AM_drawMline(&l, SecretWallColor); + else + AM_drawMline(&l, WallColor); + } else if (lines[i].locknumber > 0) { // [Dusk] specials w/ locknumbers + lock = lines[i].locknumber; + color = P_GetMapColorForLock(lock); + + AMColor c; + if (color >= 0) c.FromRGB(RPART(color), GPART(color), BPART(color)); + else c = LockedColor; + + AM_drawMline (&l, c); + } else if ((lines[i].special == Teleport || + lines[i].special == Teleport_NoFog || + lines[i].special == Teleport_ZombieChanger || + lines[i].special == Teleport_Line) && (lines[i].activation & SPAC_PlayerActivate) && am_colorset == 0) { // intra-level teleporters @@ -1988,18 +1991,18 @@ void AM_drawWalls (bool allmap) (lines[i].special == Door_Animated && lines[i].args[3] != 0) || (lines[i].special == Generic_Door && lines[i].args[4] != 0)) { - if (am_colorset == 0 || am_colorset == 3) // Raven games show door colors - { - int P_GetMapColorForLock(int lock); - - if (lines[i].special==Door_LockedRaise || lines[i].special==Door_Animated) - lock=lines[i].args[3]; - else lock=lines[i].args[4]; - - color = P_GetMapColorForLock(lock); - - AMColor c; - + if (am_colorset == 0 || am_colorset == 3) // Raven games show door colors + { + int P_GetMapColorForLock(int lock); + + if (lines[i].special==Door_LockedRaise || lines[i].special==Door_Animated) + lock=lines[i].args[3]; + else lock=lines[i].args[4]; + + color = P_GetMapColorForLock(lock); + + AMColor c; + if (color >= 0) c.FromRGB(RPART(color), GPART(color), BPART(color)); else c = LockedColor; @@ -2261,6 +2264,49 @@ void AM_drawPlayers () // //============================================================================= +void AM_drawKeys () +{ + AMColor color; + mpoint_t p; + angle_t angle; + + TThinkerIterator it; + AKey *key; + + while ((key = it.Next()) != NULL) + { + p.x = key->x >> FRACTOMAPBITS; + p.y = key->y >> FRACTOMAPBITS; + angle = key->angle; + + if (am_rotate == 1 || (am_rotate == 2 && viewactive)) + { + AM_rotatePoint (&p.x, &p.y); + angle += ANG90 - players[consoleplayer].camera->angle; + } + + color = ThingColor; + if (key->flags & MF_SPECIAL) + { + // Find the key's own color. + // Only works correctly if single-key locks have lower numbers than any-key locks. + // That is the case for all default keys, however. + int P_GetMapColorForKey (AInventory * key); + int c = P_GetMapColorForKey(key); + + if (c >= 0) color.FromRGB(RPART(c), GPART(c), BPART(c)); + else color = ThingColor_CountItem; + AM_drawLineCharacter(&EasyKey[0], EasyKey.Size(), 0, 0, color, p.x, p.y); + } + } +} + +//============================================================================= +// +// +// +//============================================================================= + void AM_drawThings () { AMColor color; @@ -2299,7 +2345,12 @@ void AM_drawThings () // That is the case for all default keys, however. if (t->IsKindOf(RUNTIME_CLASS(AKey))) { - if (am_showkeys) + if (G_SkillProperty(SKILLP_EasyKey)) + { + // Already drawn by AM_drawKeys(), so don't draw again + color.Index = -1; + } + else if (am_showkeys) { int P_GetMapColorForKey (AInventory * key); int c = P_GetMapColorForKey(static_cast(t)); @@ -2521,6 +2572,8 @@ void AM_Drawer () AM_drawWalls(allmap); AM_drawPlayers(); + if (G_SkillProperty(SKILLP_EasyKey)) + AM_drawKeys(); if (am_cheat >= 2 || allthings) AM_drawThings(); diff --git a/src/c_bind.cpp b/src/c_bind.cpp index 0aa8ddc1..0744efee 100644 --- a/src/c_bind.cpp +++ b/src/c_bind.cpp @@ -829,6 +829,7 @@ bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds) bool dclick; int dclickspot; BYTE dclickmask; + unsigned int nowtime; if (ev->type != EV_KeyDown && ev->type != EV_KeyUp) return false; @@ -841,10 +842,11 @@ bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds) dclick = false; // This used level.time which didn't work outside a level. - if (DClickTime[ev->data1] > I_MSTime() && ev->type == EV_KeyDown) + nowtime = I_MSTime(); + if (doublebinds != NULL && DClickTime[ev->data1] > nowtime && ev->type == EV_KeyDown) { // Key pressed for a double click - if (doublebinds != NULL) binding = doublebinds->GetBinding(ev->data1); + binding = doublebinds->GetBinding(ev->data1); DClicked[dclickspot] |= dclickmask; dclick = true; } @@ -853,11 +855,11 @@ bool C_DoKey (event_t *ev, FKeyBindings *binds, FKeyBindings *doublebinds) if (ev->type == EV_KeyDown) { // Key pressed for a normal press binding = binds->GetBinding(ev->data1); - DClickTime[ev->data1] = I_MSTime() + 571; + DClickTime[ev->data1] = nowtime + 571; } - else if (DClicked[dclickspot] & dclickmask) + else if (doublebinds != NULL && DClicked[dclickspot] & dclickmask) { // Key released from a double click - if (doublebinds != NULL) binding = doublebinds->GetBinding(ev->data1); + binding = doublebinds->GetBinding(ev->data1); DClicked[dclickspot] &= ~dclickmask; DClickTime[ev->data1] = 0; dclick = true; diff --git a/src/g_level.h b/src/g_level.h index 4b70f595..10dc15eb 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -545,7 +545,8 @@ enum ESkillProperty SKILLP_MonsterHealth, SKILLP_FriendlyHealth, SKILLP_NoPain, - SKILLP_ArmorFactor + SKILLP_ArmorFactor, + SKILLP_EasyKey, }; int G_SkillProperty(ESkillProperty prop); const char * G_SkillName(); @@ -564,6 +565,7 @@ struct FSkillInfo bool AutoUseHealth; bool EasyBossBrain; + bool EasyKey; int RespawnCounter; int RespawnLimit; fixed_t Aggressiveness; diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index 2c44c09f..0f77151c 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -2235,8 +2235,8 @@ class CommandDrawBar : public SBarInfoCommand { public: CommandDrawBar(SBarInfo *script) : SBarInfoCommand(script), - border(0), horizontal(false), reverse(false), foreground(-1), background(-1), - type(HEALTH), inventoryItem(NULL), interpolationSpeed(0), drawValue(0) + border(0), horizontal(false), reverse(false), foreground(-1), + background(-1), type(HEALTH), interpolationSpeed(0), drawValue(0) { } @@ -2297,28 +2297,12 @@ class CommandDrawBar : public SBarInfoCommand if(sc.Compare("health")) { type = HEALTH; - if(sc.CheckToken(TK_Identifier)) //comparing reference - { - inventoryItem = PClass::FindClass(sc.String); - if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) //must be a kind of inventory - { - sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); - inventoryItem = RUNTIME_CLASS(AInventory); - } - } + ParseComparator(sc); } else if(sc.Compare("armor")) { type = ARMOR; - if(sc.CheckToken(TK_Identifier)) - { - inventoryItem = PClass::FindClass(sc.String); - if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) //must be a kind of inventory - { - sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); - inventoryItem = RUNTIME_CLASS(AInventory); - } - } + ParseComparator(sc); } else if(sc.Compare("ammo1")) type = AMMO1; @@ -2328,11 +2312,11 @@ class CommandDrawBar : public SBarInfoCommand { sc.MustGetToken(TK_Identifier); type = AMMO; - inventoryItem = PClass::FindClass(sc.String); - if(inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(inventoryItem)) //must be a kind of ammo + data.inventoryItem = PClass::FindClass(sc.String); + if(data.inventoryItem == NULL || !RUNTIME_CLASS(AAmmo)->IsAncestorOf(data.inventoryItem)) //must be a kind of ammo { sc.ScriptMessage("'%s' is not a type of ammo.", sc.String); - inventoryItem = RUNTIME_CLASS(AAmmo); + data.inventoryItem = RUNTIME_CLASS(AAmmo); } } else if(sc.Compare("frags")) @@ -2351,21 +2335,21 @@ class CommandDrawBar : public SBarInfoCommand { type = POWERUPTIME; sc.MustGetToken(TK_Identifier); - inventoryItem = PClass::FindClass(sc.String); - if(inventoryItem == NULL || !RUNTIME_CLASS(APowerupGiver)->IsAncestorOf(inventoryItem)) + data.inventoryItem = PClass::FindClass(sc.String); + if(data.inventoryItem == NULL || !RUNTIME_CLASS(APowerupGiver)->IsAncestorOf(data.inventoryItem)) { sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String); - inventoryItem = RUNTIME_CLASS(APowerupGiver); + data.inventoryItem = RUNTIME_CLASS(APowerupGiver); } } else { type = INVENTORY; - inventoryItem = PClass::FindClass(sc.String); - if(inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(inventoryItem)) + data.inventoryItem = PClass::FindClass(sc.String); + if(data.inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(data.inventoryItem)) { sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); - inventoryItem = RUNTIME_CLASS(AInventory); + data.inventoryItem = RUNTIME_CLASS(AInventory); } } sc.MustGetToken(','); @@ -2423,9 +2407,11 @@ class CommandDrawBar : public SBarInfoCommand if(value < 0) //health shouldn't display negatives value = 0; - if(inventoryItem != NULL) + if(data.useMaximumConstant) + max = data.value; + else if(data.inventoryItem != NULL) { - AInventory *item = statusBar->CPlayer->mo->FindInventory(inventoryItem); //max comparer + AInventory *item = statusBar->CPlayer->mo->FindInventory(data.inventoryItem); //max comparer if(item != NULL) max = item->Amount; else @@ -2436,9 +2422,11 @@ class CommandDrawBar : public SBarInfoCommand break; case ARMOR: value = statusBar->armor != NULL ? statusBar->armor->Amount : 0; - if(inventoryItem != NULL) + if(data.useMaximumConstant) + max = data.value; + else if(data.inventoryItem != NULL) { - AInventory *item = statusBar->CPlayer->mo->FindInventory(inventoryItem); + AInventory *item = statusBar->CPlayer->mo->FindInventory(data.inventoryItem); if(item != NULL) max = item->Amount; else @@ -2469,7 +2457,7 @@ class CommandDrawBar : public SBarInfoCommand break; case AMMO: { - AInventory *item = statusBar->CPlayer->mo->FindInventory(inventoryItem); + AInventory *item = statusBar->CPlayer->mo->FindInventory(data.inventoryItem); if(item != NULL) { value = item->Amount; @@ -2497,7 +2485,7 @@ class CommandDrawBar : public SBarInfoCommand break; case INVENTORY: { - AInventory *item = statusBar->CPlayer->mo->FindInventory(inventoryItem); + AInventory *item = statusBar->CPlayer->mo->FindInventory(data.inventoryItem); if(item != NULL) { value = item->Amount; @@ -2514,7 +2502,7 @@ class CommandDrawBar : public SBarInfoCommand case POWERUPTIME: { //Get the PowerupType and check to see if the player has any in inventory. - APowerupGiver *powerupGiver = (APowerupGiver*) GetDefaultByType(inventoryItem); + APowerupGiver *powerupGiver = (APowerupGiver*) GetDefaultByType(data.inventoryItem); const PClass *powerupType = powerupGiver->PowerupType; APowerup *powerup = (APowerup*) statusBar->CPlayer->mo->FindInventory(powerupType); if(powerup != NULL && powerupType != NULL && powerupGiver != NULL) @@ -2566,6 +2554,29 @@ class CommandDrawBar : public SBarInfoCommand drawValue = value; } protected: + void ParseComparator(FScanner &sc) + { + bool extendedSyntax = sc.CheckToken('('); + + if(sc.CheckToken(TK_Identifier)) //comparing reference + { + data.inventoryItem = PClass::FindClass(sc.String); + if(data.inventoryItem == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(data.inventoryItem)) //must be a kind of inventory + { + sc.ScriptMessage("'%s' is not a type of inventory item.", sc.String); + data.inventoryItem = RUNTIME_CLASS(AInventory); + } + } + else if(extendedSyntax && sc.CheckToken(TK_IntConst)) + { + data.useMaximumConstant = true; + data.value = sc.Number; + } + + if(extendedSyntax) + sc.MustGetToken(')'); + } + enum ValueType { HEALTH, @@ -2584,13 +2595,28 @@ class CommandDrawBar : public SBarInfoCommand SAVEPERCENT }; + struct AdditionalData + { + public: + AdditionalData() : useMaximumConstant(false) + { + } + + bool useMaximumConstant; + union + { + const PClass *inventoryItem; + int value; + }; + }; + unsigned int border; bool horizontal; bool reverse; int foreground; int background; ValueType type; - const PClass *inventoryItem; + AdditionalData data; SBarInfoCoordinate x; SBarInfoCoordinate y; diff --git a/src/g_skill.cpp b/src/g_skill.cpp index cac38563..46b9a170 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -66,6 +66,7 @@ void FMapInfoParser::ParseSkill () skill.FastMonsters = false; skill.DisableCheats = false; skill.EasyBossBrain = false; + skill.EasyKey = false; skill.AutoUseHealth = false; skill.RespawnCounter = 0; skill.RespawnLimit = 0; @@ -125,6 +126,10 @@ void FMapInfoParser::ParseSkill () { skill.EasyBossBrain = true; } + else if (sc.Compare ("easykey")) + { + skill.EasyKey = true; + } else if (sc.Compare("autousehealth")) { skill.AutoUseHealth = true; @@ -351,6 +356,9 @@ int G_SkillProperty(ESkillProperty prop) case SKILLP_EasyBossBrain: return AllSkills[gameskill].EasyBossBrain; + case SKILLP_EasyKey: + return AllSkills[gameskill].EasyKey; + case SKILLP_SpawnFilter: return AllSkills[gameskill].SpawnFilter; @@ -428,6 +436,7 @@ FSkillInfo &FSkillInfo::operator=(const FSkillInfo &other) DisableCheats = other.DisableCheats; AutoUseHealth = other.AutoUseHealth; EasyBossBrain = other.EasyBossBrain; + EasyKey = other.EasyKey; RespawnCounter= other.RespawnCounter; RespawnLimit= other.RespawnLimit; Aggressiveness= other.Aggressiveness; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 639f7031..5c0a5aa6 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1529,11 +1529,11 @@ void FBehavior::LoadScriptsDirectory () } } - // Load script var counts + // Load script var counts. (Only recorded for scripts that use more than LOCAL_SIZE variables.) scripts.b = FindChunk (MAKE_ID('S','V','C','T')); if (scripts.dw != NULL) { - max = scripts.dw[1]; + max = scripts.dw[1] / 4; scripts.dw += 2; for (i = max; i > 0; --i, scripts.w += 2) { @@ -1544,6 +1544,27 @@ void FBehavior::LoadScriptsDirectory () } } } + + // Load script names (if any) + scripts.b = FindChunk(MAKE_ID('S','N','A','M')); + if (scripts.dw != NULL) + { + for (i = 0; i < NumScripts; ++i) + { + // ACC stores script names as an index into the SNAM chunk, with the first index as + // -1 and counting down from there. We convert this from an index into SNAM into + // a negative index into the global name table. + if (Scripts[i].Number < 0) + { + const char *str = (const char *)(scripts.b + 8 + scripts.dw[3 + (-Scripts[i].Number - 1)]); + FName name(str); + Scripts[i].Number = -name; + } + } + // We need to resort scripts, because the new numbers for named scripts likely + // do not match the order they were originally in. + qsort (Scripts, NumScripts, sizeof(ScriptPtr), SortScripts); + } } int STACK_ARGS FBehavior::SortScripts (const void *a, const void *b) @@ -1621,8 +1642,8 @@ bool FBehavior::IsGood () const ScriptPtr *FBehavior::FindScript (int script) const { - const ScriptPtr *ptr = BinarySearch - ((ScriptPtr *)Scripts, NumScripts, &ScriptPtr::Number, (WORD)script); + const ScriptPtr *ptr = BinarySearch + ((ScriptPtr *)Scripts, NumScripts, &ScriptPtr::Number, script); // If the preceding script has the same number, return it instead. // See the note by the script sorting above for why. @@ -1859,6 +1880,50 @@ void FBehavior::StaticStopMyScripts (AActor *actor) } } +//========================================================================== +// +// SerializeScriptNumber +// +// Serializes a script number. If it's negative, it's really a name, so +// that will get serialized after it. +// +//========================================================================== + +static void SerializeScriptNumber(FArchive &arc, int &scriptnum, bool was2byte) +{ + if (SaveVersion < 3359) + { + if (was2byte) + { + WORD oldver; + arc << oldver; + scriptnum = oldver; + } + else + { + arc << scriptnum; + } + } + else + { + arc << scriptnum; + // If the script number is negative, then it's really a name. + // So read/store the name after it. + if (scriptnum < 0) + { + if (arc.IsStoring()) + { + arc.WriteName(FName(ENamedName(-scriptnum)).GetChars()); + } + else + { + const char *nam = arc.ReadName(); + scriptnum = -FName(nam); + } + } + } +} + //---- The ACS Interpreter ----// IMPLEMENT_POINTY_CLASS (DACSThinker) @@ -1880,8 +1945,7 @@ DACSThinker::DACSThinker () ActiveThinker = this; Scripts = NULL; LastScript = NULL; - for (int i = 0; i < 1000; i++) - RunningScripts[i] = NULL; + RunningScripts.Clear(); } } @@ -1893,27 +1957,34 @@ DACSThinker::~DACSThinker () void DACSThinker::Serialize (FArchive &arc) { + int scriptnum; + Super::Serialize (arc); arc << Scripts << LastScript; if (arc.IsStoring ()) { - WORD i; - for (i = 0; i < 1000; i++) + ScriptMap::Iterator it(RunningScripts); + ScriptMap::Pair *pair; + + while (it.NextPair(pair)) { - if (RunningScripts[i]) - arc << RunningScripts[i] << i; + assert(pair->Value != NULL); + arc << pair->Value; + scriptnum = pair->Key; + SerializeScriptNumber(arc, scriptnum, true); } DLevelScript *nilptr = NULL; arc << nilptr; } - else + else // Loading { - WORD scriptnum; DLevelScript *script = NULL; + RunningScripts.Clear(); + arc << script; while (script) { - arc << scriptnum; + SerializeScriptNumber(arc, scriptnum, true); RunningScripts[scriptnum] = script; arc << script; } @@ -1975,8 +2046,9 @@ void DLevelScript::Serialize (FArchive &arc) DWORD i; Super::Serialize (arc); - arc << next << prev - << script; + arc << next << prev; + + SerializeScriptNumber(arc, script, false); arc << state << statedata @@ -3713,13 +3785,13 @@ int DLevelScript::RunScript () case SCRIPT_ScriptWaitPre: // Wait for a script to start running, then enter state scriptwait - if (controller->RunningScripts[statedata]) + if (controller->RunningScripts.CheckKey(statedata) != NULL) state = SCRIPT_ScriptWait; break; case SCRIPT_ScriptWait: // Wait for a script to stop running, then enter state running - if (controller->RunningScripts[statedata]) + if (controller->RunningScripts.CheckKey(statedata) != NULL) return resultValue; state = SCRIPT_Running; @@ -5016,7 +5088,7 @@ int DLevelScript::RunScript () case PCD_SCRIPTWAIT: statedata = STACK(1); - if (controller->RunningScripts[statedata]) + if (controller->RunningScripts.CheckKey(statedata) != NULL) state = SCRIPT_ScriptWait; else state = SCRIPT_ScriptWaitPre; @@ -6960,8 +7032,12 @@ int DLevelScript::RunScript () if (state == SCRIPT_PleaseRemove) { Unlink (); - if (controller->RunningScripts[script] == this) - controller->RunningScripts[script] = NULL; + DLevelScript **running; + if ((running = controller->RunningScripts.CheckKey(script)) != NULL && + *running == this) + { + controller->RunningScripts.Remove(script); + } } else { @@ -6977,13 +7053,14 @@ static DLevelScript *P_GetScriptGoing (AActor *who, line_t *where, int num, cons bool backSide, int arg0, int arg1, int arg2, int always) { DACSThinker *controller = DACSThinker::ActiveThinker; + DLevelScript **running; - if (controller && !always && controller->RunningScripts[num]) + if (controller && !always && (running = controller->RunningScripts.CheckKey(num)) != NULL) { - if (controller->RunningScripts[num]->GetState () == DLevelScript::SCRIPT_Suspended) + if ((*running)->GetState() == DLevelScript::SCRIPT_Suspended) { - controller->RunningScripts[num]->SetState (DLevelScript::SCRIPT_Running); - return controller->RunningScripts[num]; + (*running)->SetState(DLevelScript::SCRIPT_Running); + return *running; } return NULL; } @@ -6999,6 +7076,7 @@ DLevelScript::DLevelScript (AActor *who, line_t *where, int num, const ScriptPtr new DACSThinker; script = num; + assert(code->VarCount >= code->ArgCount); numlocalvars = code->VarCount; localvars = new SDWORD[code->VarCount]; if (code->VarCount > 0) @@ -7043,9 +7121,12 @@ DLevelScript::DLevelScript (AActor *who, line_t *where, int num, const ScriptPtr static void SetScriptState (int script, DLevelScript::EScriptState state) { DACSThinker *controller = DACSThinker::ActiveThinker; + DLevelScript **running; - if (controller != NULL && controller->RunningScripts[script]) - controller->RunningScripts[script]->SetState (state); + if (controller != NULL && (running = controller->RunningScripts.CheckKey(script)) != NULL) + { + (*running)->SetState (state); + } } void P_DoDeferedScripts () diff --git a/src/p_acs.h b/src/p_acs.h index 245d90c4..737501a7 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -76,18 +76,18 @@ void P_ClearACSVars(bool); // The in-memory version struct ScriptPtr { - WORD Number; + int Number; + DWORD Address; BYTE Type; BYTE ArgCount; WORD VarCount; WORD Flags; - DWORD Address; }; // The present ZDoom version struct ScriptPtr3 { - WORD Number; + SWORD Number; BYTE Type; BYTE ArgCount; DWORD Address; @@ -747,7 +747,8 @@ public: void Serialize (FArchive &arc); void Tick (); - DLevelScript *RunningScripts[1000]; // Array of all synchronous scripts + typedef TMap ScriptMap; + ScriptMap RunningScripts; // Array of all synchronous scripts static TObjPtr ActiveThinker; void DumpScriptStatus(); diff --git a/src/po_man.cpp b/src/po_man.cpp index 8a18269e..d5219e51 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1295,7 +1295,8 @@ bool FPolyObj::CheckMobjBlocking (side_t *sd) fixed_t top = -INT_MAX, bottom = INT_MAX; bool above; // [TN] Check wether this actor gets blocked by the line. - if(!(ld->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING)) + if (ld->backsector != NULL && + !(ld->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING)) && !(ld->flags & ML_BLOCK_PLAYERS && mobj->player) && !(ld->flags & ML_BLOCKMONSTERS && mobj->flags3 & MF3_ISMONSTER) && !((mobj->flags & MF_FLOAT) && (ld->flags & ML_BLOCK_FLOATERS)) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 4af92f46..726d71ef 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -101,7 +101,7 @@ extern float S_GetMusicVolume (const char *music); // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- -static bool S_CheckSoundLimit(sfxinfo_t *sfx, const FVector3 &pos, int near_limit, float limit_range); +static bool S_CheckSoundLimit(sfxinfo_t *sfx, const FVector3 &pos, int near_limit, float limit_range, AActor *actor, int channel); static bool S_IsChannelUsed(AActor *actor, int channel, int *seen); static void S_ActivatePlayList(bool goBack); static void CalcPosVel(FSoundChan *chan, FVector3 *pos, FVector3 *vel); @@ -952,7 +952,7 @@ static FSoundChan *S_StartSound(AActor *actor, const sector_t *sec, const FPolyO // If this sound doesn't like playing near itself, don't play it if // that's what would happen. - if (near_limit > 0 && S_CheckSoundLimit(sfx, pos, near_limit, limit_range)) + if (near_limit > 0 && S_CheckSoundLimit(sfx, pos, near_limit, limit_range, actor, channel)) { chanflags |= CHAN_EVICTED; } @@ -1157,7 +1157,7 @@ void S_RestartSound(FSoundChan *chan) // If this sound doesn't like playing near itself, don't play it if // that's what would happen. - if (chan->NearLimit > 0 && S_CheckSoundLimit(&S_sfx[chan->SoundID], pos, chan->NearLimit, chan->LimitRange)) + if (chan->NearLimit > 0 && S_CheckSoundLimit(&S_sfx[chan->SoundID], pos, chan->NearLimit, chan->LimitRange, NULL, 0)) { return; } @@ -1389,12 +1389,19 @@ bool S_CheckSingular(int sound_id) // // Limits the number of nearby copies of a sound that can play near // each other. If there are NearLimit instances of this sound already -// playing within 256 units of the new sound, the new sound will not -// start. +// playing within sqrt(limit_range) (typically 256 units) of the new sound, the +// new sound will not start. +// +// If an actor is specified, and it is already playing the same sound on +// the same channel, this sound will not be limited. In this case, we're +// restarting an already playing sound, so there's no need to limit it. +// +// Returns true if the sound should not play. // //========================================================================== -bool S_CheckSoundLimit(sfxinfo_t *sfx, const FVector3 &pos, int near_limit, float limit_range) +bool S_CheckSoundLimit(sfxinfo_t *sfx, const FVector3 &pos, int near_limit, float limit_range, + AActor *actor, int channel) { FSoundChan *chan; int count; @@ -1405,6 +1412,12 @@ bool S_CheckSoundLimit(sfxinfo_t *sfx, const FVector3 &pos, int near_limit, floa { FVector3 chanorigin; + if (actor != NULL && chan->EntChannel == channel && + chan->SourceType == SOURCE_Actor && chan->Actor == actor) + { // We are restarting a playing sound. Always let it play. + return false; + } + CalcPosVel(chan, &chanorigin, NULL); if ((chanorigin - pos).LengthSquared() <= limit_range) { diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 5af94a34..8c62e3b5 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -1725,8 +1725,6 @@ FISoundChannel *FMODSoundRenderer::StartSound(SoundHandle sfx, float vol, int pi // //========================================================================== -CVAR(Float, snd_3dspread, 180, 0) - FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *listener, float vol, FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, @@ -1811,7 +1809,6 @@ FISoundChannel *FMODSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener * if (mode & FMOD_3D) { chan->set3DAttributes((FMOD_VECTOR *)&pos[0], (FMOD_VECTOR *)&vel[0]); - chan->set3DSpread(snd_3dspread); } if (!HandleChannelDelay(chan, reuse_chan, flags & (SNDF_ABSTIME | SNDF_LOOP), freq)) { diff --git a/src/svnrevision.h b/src/svnrevision.h index 2d0fe354..1ffb76ec 100644 --- a/src/svnrevision.h +++ b/src/svnrevision.h @@ -3,5 +3,5 @@ // This file was automatically generated by the // updaterevision tool. Do not edit by hand. -#define ZD_SVN_REVISION_STRING "3350" -#define ZD_SVN_REVISION_NUMBER 3350 +#define ZD_SVN_REVISION_STRING "3360" +#define ZD_SVN_REVISION_NUMBER 3360 diff --git a/src/v_text.cpp b/src/v_text.cpp index b4d1e533..c5208be3 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -78,7 +78,7 @@ void STACK_ARGS DCanvas::DrawChar (FFont *font, int normalcolor, int x, int y, B // // Write a string using the given font // -void DCanvas::DrawTextV(FFont *font, int normalcolor, int x, int y, const char *string, uint32 tag1, va_list taglist) +void DCanvas::DrawTextV(FFont *font, int normalcolor, int x, int y, const char *string, va_list taglist) { INTBOOL boolval; va_list tags; @@ -122,7 +122,7 @@ void DCanvas::DrawTextV(FFont *font, int normalcolor, int x, int y, const char * #else tags = taglist; #endif - tag = tag1; + tag = va_arg(tags, uint32); while (tag != TAG_DONE) { @@ -209,6 +209,7 @@ void DCanvas::DrawTextV(FFont *font, int normalcolor, int x, int y, const char * } tag = va_arg (tags, uint32); } + va_end(tags); height *= scaley; @@ -242,7 +243,6 @@ void DCanvas::DrawTextV(FFont *font, int normalcolor, int x, int y, const char * #else tags = taglist; #endif - tag = tag1; if (forcedwidth) { w = forcedwidth; @@ -262,21 +262,22 @@ void DCanvas::DrawTextV(FFont *font, int normalcolor, int x, int y, const char * } cx += (w + kerning) * scalex; } + va_end(taglist); } -void STACK_ARGS DCanvas::DrawText (FFont *font, int normalcolor, int x, int y, const char *string, uint32 tag, ...) +void STACK_ARGS DCanvas::DrawText (FFont *font, int normalcolor, int x, int y, const char *string, ...) { va_list tags; - va_start(tags, tag); - DrawTextV(font, normalcolor, x, y, string, tag, tags); + va_start(tags, string); + DrawTextV(font, normalcolor, x, y, string, tags); } // A synonym so that this can still be used in files that #include Windows headers -void STACK_ARGS DCanvas::DrawTextA (FFont *font, int normalcolor, int x, int y, const char *string, uint32 tag, ...) +void STACK_ARGS DCanvas::DrawTextA (FFont *font, int normalcolor, int x, int y, const char *string, ...) { va_list tags; - va_start(tags, tag); - DrawTextV(font, normalcolor, x, y, string, tag, tags); + va_start(tags, string); + DrawTextV(font, normalcolor, x, y, string, tags); } // diff --git a/src/v_video.h b/src/v_video.h index 50a81f13..6d97256f 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -214,11 +214,11 @@ public: void VirtualToRealCoordsInt(int &x, int &y, int &w, int &h, int vwidth, int vheight, bool vbottom=false, bool handleaspect=true) const; // 2D Text drawing - void STACK_ARGS DrawText (FFont *font, int normalcolor, int x, int y, const char *string, uint32 tag, ...); + void STACK_ARGS DrawText (FFont *font, int normalcolor, int x, int y, const char *string, ...); #ifndef DrawText // See WinUser.h for the definition of DrawText as a macro - void STACK_ARGS DrawTextA (FFont *font, int normalcolor, int x, int y, const char *string, uint32 tag, ...); + void STACK_ARGS DrawTextA (FFont *font, int normalcolor, int x, int y, const char *string, ...); #endif - void DrawTextV (FFont *font, int normalcolor, int x, int y, const char *string, uint32 tag, va_list tags); + void DrawTextV (FFont *font, int normalcolor, int x, int y, const char *string, va_list tags); void STACK_ARGS DrawChar (FFont *font, int normalcolor, int x, int y, BYTE character, ...); struct DrawParms diff --git a/wadsrc/static/maparrows/ravenkey.txt b/wadsrc/static/maparrows/ravenkey.txt new file mode 100644 index 00000000..d66a6434 --- /dev/null +++ b/wadsrc/static/maparrows/ravenkey.txt @@ -0,0 +1,9 @@ +( 0, 0 ), ( 0.25, -0.5 ) +( 0.25, -0.5 ), ( 0.5, -0.5 ) +( 0.5, -0.5 ), ( 0.5, 0.5 ) +( 0.5, 0.5 ), ( 0.25, 0.5 ) +( 0.25, 0.5 ), ( 0, 0 ) // handle part type thing +( 0, 0 ), ( -1, 0 ) // stem +( -1, 0 ), ( -1, -0.5 ) // end lockpick part +( -0.75, 0 ), ( -0.75, -0.25 ) + diff --git a/wadsrc/static/mapinfo/heretic.txt b/wadsrc/static/mapinfo/heretic.txt index 84dd4552..196e81c5 100644 --- a/wadsrc/static/mapinfo/heretic.txt +++ b/wadsrc/static/mapinfo/heretic.txt @@ -75,6 +75,7 @@ skill baby EasyBossBrain SpawnFilter = Baby Name = "$MNU_WETNURSE" + EasyKey } skill easy