diff --git a/specs/usdf.txt b/specs/usdf.txt index 093c9e7d74..1367ccfbf9 100644 --- a/specs/usdf.txt +++ b/specs/usdf.txt @@ -87,16 +87,14 @@ conversation // Starts a dialog. page // Starts a new page. Pages are automatically numbered starting at 1. { - name = ; // Name that goes in the upper left hand corner - panel = ; // Name of lump to render as the background. - voice = ; // Narration sound lump. - dialog = ; // Dialog of the page. - goodbye = ; // Custom goodbye message. If omitted then the - // generic goodbyes will be displayed instead. - drop = ; // mobj for the object to drop if the actor is - // killed. - link = ; // Page to jump to if all ifitem conditions are - // satisified. + name = ; // Name that goes in the upper left hand corner + panel = ; // Name of lump to render as the background. + voice = ; // Narration sound lump. + dialog = ; // Dialog of the page. + drop = ; // mobj for the object to drop if the actor is + // killed. + link = ; // Page to jump to if all ifitem conditions are + // satisified. // jumps to the specified page if the player has the specified amount // or more of item in their inventory. This can be repeated as many diff --git a/specs/usdf_zdoom.txt b/specs/usdf_zdoom.txt index c106cdd1af..f800b5ae79 100644 --- a/specs/usdf_zdoom.txt +++ b/specs/usdf_zdoom.txt @@ -76,8 +76,8 @@ namespace = "ZDoom"; III.A : Conversations --------------------- -This block only lists the newly added fields. Currently ZDoom only adds one -field to the specification: +This block only lists the newly added fields. Currently ZDoom only adds a few +fields to the specification: conversation // Starts a dialog. { @@ -86,6 +86,35 @@ conversation // Starts a dialog. // the standard conversation ID ('actor' property) is used instead // for this purpose but since 'ZDoom' namespace requires the actor // to be a class name it needs a separate field for this. + + page + { + goodbye = ; // Custom goodbye message. If omitted then the + // generic goodbyes will be displayed instead. + + choice + { + // The amount of an item needed for this option to become available. + // You can have as many as needed. All require blocks must be satisfied + // to show this option. + require + { + item = ; // Item that is required to show this option. + amount = ; // Minimum amount of the item needed. + } + + // The undesired amount of an item. This option will become available + // if you have less than the specified amount. You can have as many + // as needed. All exclude blocks must be satisfied to show this option. + // Note: if both require and exclude are defined then all require + // and all exclude blocks must be satisfied to show this option. + exclude + { + item = ; // Item that is unwanted to show this option. + amount = ; // Unwanted minimum amount of the item. + } + } + } } =============================================================================== diff --git a/src/asm_ia32/tmap2.asm b/src/asm_ia32/tmap2.asm index 9a7aa55346..ab1695d3cd 100644 --- a/src/asm_ia32/tmap2.asm +++ b/src/asm_ia32/tmap2.asm @@ -198,7 +198,10 @@ SetTiltedSpanSize: mov [y8+2],cl mov [y9+2],cl mov [y10+2],cl + cmp eax,0 ; if x bits is 0, mask must be 0 too. + jz .notted not eax +.notted: pop ecx mov [m1+2],eax diff --git a/src/doomstat.h b/src/doomstat.h index bbb323c7e3..22ee4fdb49 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -71,6 +71,9 @@ extern bool netgame; // Bot game? Like netgame, but doesn't involve network communication. extern bool multiplayer; +// [SP] Map dm/coop implementation - invokes fake multiplayer without bots +extern bool multiplayernext; + // Flag: true only if started as net deathmatch. EXTERN_CVAR (Int, deathmatch) diff --git a/src/g_game.cpp b/src/g_game.cpp index b0c8775fc5..ec79d59e60 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -164,6 +164,7 @@ bool viewactive; bool netgame; // only true if packets are broadcast bool multiplayer; +bool multiplayernext = false; // [SP] Map coop/dm implementation player_t players[MAXPLAYERS]; bool playeringame[MAXPLAYERS]; diff --git a/src/g_level.cpp b/src/g_level.cpp index d3a8c4015a..9e8448879f 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -90,6 +90,8 @@ #include "g_hub.h" +#include + void STAT_StartNewGame(const char *lev); void STAT_ChangeLevel(const char *newl); @@ -181,6 +183,16 @@ CCMD (map) } else { + if (argv.argc() > 2 && stricmp(argv[2], "coop") == 0) + { + deathmatch = false; + multiplayernext = true; + } + else if (argv.argc() > 2 && stricmp(argv[2], "dm") == 0) + { + deathmatch = true; + multiplayernext = true; + } G_DeferedInitNew (argv[1]); } } @@ -192,7 +204,7 @@ CCMD (map) } else { - Printf ("Usage: map \n"); + Printf ("Usage: map [coop|dm]\n"); } } @@ -218,6 +230,16 @@ CCMD(recordmap) } else { + if (argv.argc() > 3 && stricmp(argv[3], "coop") == 0) + { + deathmatch = false; + multiplayernext = true; + } + else if (argv.argc() > 3 && stricmp(argv[3], "dm") == 0) + { + deathmatch = true; + multiplayernext = true; + } G_DeferedInitNew(argv[2]); gameaction = ga_recordgame; newdemoname = argv[1]; @@ -232,7 +254,7 @@ CCMD(recordmap) } else { - Printf("Usage: recordmap \n"); + Printf("Usage: recordmap [coop|dm]\n"); } } @@ -258,13 +280,23 @@ CCMD (open) } else { + if (argv.argc() > 2 && stricmp(argv[2], "coop") == 0) + { + deathmatch = false; + multiplayernext = true; + } + else if (argv.argc() > 2 && stricmp(argv[2], "dm") == 0) + { + deathmatch = true; + multiplayernext = true; + } gameaction = ga_newgame2; d_skill = -1; } } else { - Printf ("Usage: open \n"); + Printf ("Usage: open [coop|dm]\n"); } } @@ -293,7 +325,8 @@ void G_NewInit () G_ClearSnapshots (); ST_SetNeedRefresh(); netgame = false; - multiplayer = false; + multiplayer = multiplayernext; + multiplayernext = false; if (demoplayback) { C_RestoreCVars (); diff --git a/src/g_shared/a_weapons.cpp b/src/g_shared/a_weapons.cpp index edd250debd..b1ede01874 100644 --- a/src/g_shared/a_weapons.cpp +++ b/src/g_shared/a_weapons.cpp @@ -640,6 +640,7 @@ void AWeapon::PostMorphWeapon () pspr = Owner->player->GetPSprite(PSP_WEAPON); pspr->y = WEAPONBOTTOM; + pspr->ResetInterpolation(); pspr->SetState(GetUpState()); } diff --git a/src/namedef.h b/src/namedef.h index eab87c503b..8def090fa4 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -585,6 +585,8 @@ xx(Ifitem) xx(Choice) xx(Link) xx(Goodbye) +xx(Require) +xx(Exclude) // Special menus xx(Mainmenu) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index f36aaaf69a..1a60a0c4fb 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -375,6 +375,7 @@ void ACSStringPool::Clear() int ACSStringPool::AddString(const char *str) { + if (str == nullptr) str = ""; size_t len = strlen(str); unsigned int h = SuperFastHash(str, len); unsigned int bucketnum = h % NUM_BUCKETS; @@ -791,6 +792,10 @@ void ACSStringPool::WriteStrings(FSerializer &file, const char *key) const { if (file.BeginObject(nullptr)) { + if (i == 430) + { + int a = 0; + } file("index", i) ("string", entry->Str) ("lockcount", entry->LockCount) @@ -5345,7 +5350,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) case ACSF_PlaySound: case ACSF_PlayActorSound: - // PlaySound(tid, "SoundName", channel, volume, looping, attenuation) + // PlaySound(tid, "SoundName", channel, volume, looping, attenuation, local) { FSoundID sid; @@ -5366,6 +5371,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) float vol = argCount > 3 ? ACSToFloat(args[3]) : 1.f; INTBOOL looping = argCount > 4 ? args[4] : false; float atten = argCount > 5 ? ACSToFloat(args[5]) : ATTN_NORM; + INTBOOL local = argCount > 6 ? args[6] : false; if (args[0] == 0) { @@ -5382,11 +5388,11 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) { if (!looping) { - S_Sound(spot, chan, sid, vol, atten); + S_PlaySound(spot, chan, sid, vol, atten, local); } else if (!S_IsActorPlayingSomething(spot, chan & 7, sid)) { - S_Sound(spot, chan | CHAN_LOOP, sid, vol, atten); + S_PlaySound(spot, chan | CHAN_LOOP, sid, vol, atten, local); } } } diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index c6bc8215b0..73cade49a4 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -1032,16 +1032,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PlaySound) PARAM_FLOAT_OPT (volume) { volume = 1; } PARAM_BOOL_OPT (looping) { looping = false; } PARAM_FLOAT_OPT (attenuation) { attenuation = ATTN_NORM; } + PARAM_BOOL_OPT (local) { local = false; } if (!looping) { - S_Sound (self, channel, soundid, (float)volume, (float)attenuation); + S_PlaySound(self, channel, soundid, (float)volume, (float)attenuation, local); } else { if (!S_IsActorPlayingSomething (self, channel&7, soundid)) { - S_Sound (self, channel | CHAN_LOOP, soundid, (float)volume, (float)attenuation); + S_PlaySound(self, channel | CHAN_LOOP, soundid, (float)volume, (float)attenuation, local); } } return 0; diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index f216d9d78a..0bc2b98a87 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -516,6 +516,8 @@ static void ParseReplies (FStrifeDialogueReply **replyptr, Response *responses) reply->ItemCheck[k].Item = dyn_cast(GetStrifeType(rsp->Item[k])); reply->ItemCheck[k].Amount = rsp->Count[k]; } + reply->ItemCheckRequire.Clear(); + reply->ItemCheckExclude.Clear(); // If the first item check has a positive amount required, then // add that to the reply string. Otherwise, use the reply as-is. @@ -656,6 +658,38 @@ CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE) else if (self > 1.f) self = 1.f; } +//============================================================================ +// +// ShouldSkipReply +// +// Determines whether this reply should be skipped or not. +// +//============================================================================ + +static bool ShouldSkipReply(FStrifeDialogueReply *reply, player_t *player) +{ + if (reply->Reply == nullptr) + return true; + + int i; + for (i = 0; i < (int)reply->ItemCheckRequire.Size(); ++i) + { + if (!CheckStrifeItem(player, reply->ItemCheckRequire[i].Item, reply->ItemCheckRequire[i].Amount)) + { + return true; + } + } + + for (i = 0; i < (int)reply->ItemCheckExclude.Size(); ++i) + { + if (CheckStrifeItem(player, reply->ItemCheckExclude[i].Item, reply->ItemCheckExclude[i].Amount)) + { + return true; + } + } + return false; +} + //============================================================================ // // The conversation menu @@ -673,6 +707,7 @@ class DConversationMenu : public DMenu bool mShowGold; FStrifeDialogueNode *mCurNode; int mYpos; + player_t *mPlayer; public: static int mSelection; @@ -683,9 +718,10 @@ public: // //============================================================================= - DConversationMenu(FStrifeDialogueNode *CurNode) + DConversationMenu(FStrifeDialogueNode *CurNode, player_t *player) { mCurNode = CurNode; + mPlayer = player; mDialogueLines = NULL; mShowGold = false; @@ -720,7 +756,7 @@ public: int i,j; for (reply = CurNode->Children, i = 1; reply != NULL; reply = reply->Next) { - if (reply->Reply == NULL) + if (ShouldSkipReply(reply, mPlayer)) { continue; } @@ -778,6 +814,13 @@ public: } ConversationMenuY = mYpos; //ConversationMenu.indent = 50; + + // Because replies can be selectively hidden mResponses.Size() won't be consistent. + // So make sure mSelection doesn't exceed mResponses.Size(). [FishyClockwork] + if (mSelection >= (int)mResponses.Size()) + { + mSelection = mResponses.Size() - 1; + } } //============================================================================= @@ -839,12 +882,24 @@ public: } else { - // Send dialogue and reply numbers across the wire. assert((unsigned)mCurNode->ThisNodeNum < StrifeDialogues.Size()); assert(StrifeDialogues[mCurNode->ThisNodeNum] == mCurNode); + + // This is needed because mSelection represents the replies currently being displayed which will + // not match up with what's supposed to be selected if there are any hidden/skipped replies. [FishyClockwork] + FStrifeDialogueReply *reply = mCurNode->Children; + int replynum = mSelection; + for (int i = 0; i <= mSelection && reply != nullptr; reply = reply->Next) + { + if (ShouldSkipReply(reply, mPlayer)) + replynum++; + else + i++; + } + // Send dialogue and reply numbers across the wire. Net_WriteByte(DEM_CONVREPLY); Net_WriteWord(mCurNode->ThisNodeNum); - Net_WriteByte(mSelection); + Net_WriteByte(replynum); } Close(); return true; @@ -1169,7 +1224,7 @@ void P_StartConversation (AActor *npc, AActor *pc, bool facetalker, bool saveang S_Sound (npc, CHAN_VOICE|CHAN_NOPAUSE, CurNode->SpeakerVoice, 1, ATTN_NORM); } - DConversationMenu *cmenu = new DConversationMenu(CurNode); + DConversationMenu *cmenu = new DConversationMenu(CurNode, pc->player); if (CurNode != PrevNode) diff --git a/src/p_conversation.h b/src/p_conversation.h index 5b068fb04b..bd674aa101 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -45,6 +45,8 @@ struct FStrifeDialogueReply int ActionSpecial; int Args[5]; TArray ItemCheck; + TArray ItemCheckRequire; + TArray ItemCheckExclude; char *Reply; char *QuickYes; int NextNode; // index into StrifeDialogues diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index abbd2284ee..2e591e20d9 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -262,8 +262,7 @@ void DPSprite::NewTick() while (pspr) { pspr->processPending = true; - pspr->oldx = pspr->x; - pspr->oldy = pspr->y; + pspr->ResetInterpolation(); pspr = pspr->Next; } diff --git a/src/p_pspr.h b/src/p_pspr.h index 084fe8fcee..4b50d9d0c2 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -29,11 +29,8 @@ #define WEAPONBOTTOM 128. -// [RH] +0x6000 helps it meet the screen bottom -// at higher resolutions while still being in -// the right spot at 320x200. -#define WEAPONTOP (32+6./16) - +#define WEAPONTOP 32. +#define WEAPON_FUDGE_Y 0.375 class AInventory; // @@ -78,6 +75,7 @@ public: DPSprite* GetNext() { return Next; } AActor* GetCaller() { return Caller; } void SetCaller(AActor *newcaller) { Caller = newcaller; } + void ResetInterpolation() { oldx = x; oldy = y; } double x, y; double oldx, oldy; diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index dccec7c210..d40c542a14 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -76,11 +76,11 @@ class USDFParser : public UDMFParserBase //=========================================================================== // - // Parse a cost block + // Parse a cost/require/exclude block // //=========================================================================== - bool ParseCost(FStrifeDialogueReply *response) + bool ParseCostRequireExclude(FStrifeDialogueReply *response, FName type) { FStrifeDialogueItemCheck check; check.Item = NULL; @@ -101,7 +101,12 @@ class USDFParser : public UDMFParserBase } } - response->ItemCheck.Push(check); + switch (type) + { + case NAME_Cost: response->ItemCheck.Push(check); break; + case NAME_Require: response->ItemCheckRequire.Push(check); break; + case NAME_Exclude: response->ItemCheckExclude.Push(check); break; + } return true; } @@ -206,8 +211,15 @@ class USDFParser : public UDMFParserBase switch(key) { case NAME_Cost: - ParseCost(reply); - break; + case NAME_Require: + case NAME_Exclude: + // Require and Exclude are exclusive to namespace ZDoom. [FishyClockwork] + if (key == NAME_Cost || namespace_bits == Zd) + { + ParseCostRequireExclude(reply, key); + break; + } + // Intentional fall-through default: sc.UnGet(); @@ -333,7 +345,11 @@ class USDFParser : public UDMFParserBase break; case NAME_Goodbye: - Goodbye = CheckString(key); + // Custom goodbyes are exclusive to namespace ZDoom. [FishyClockwork] + if (namespace_bits == Zd) + { + Goodbye = CheckString(key); + } break; } } diff --git a/src/posix/zdoom.xpm b/src/posix/zdoom.xpm new file mode 100644 index 0000000000..eae49eb77f --- /dev/null +++ b/src/posix/zdoom.xpm @@ -0,0 +1,83 @@ +/* XPM */ +static char * zdoom_xpm[] = { +"48 48 32 1", +" c None", +". c #ADA990", +"+ c #999966", +"@ c #666666", +"# c #393939", +"$ c #555555", +"% c #996666", +"& c #777777", +"* c #5F5F5F", +"= c #333333", +"- c #4D4D4D", +"; c #868686", +"> c #969696", +", c #1C1C1C", +"' c #339933", +") c #336633", +"! c #66CC66", +"~ c #66FF66", +"{ c #66CC33", +"] c #222222", +"^ c #333300", +"/ c #292929", +"( c #040404", +"_ c #0C0C0C", +": c #663333", +"< c #996633", +"[ c #CC9966", +"} c #CC6633", +"| c #CC9999", +"1 c #FFCC99", +"2 c #FF9966", +"3 c #FFCCCC", +" ... ", +" ++@##$+ ", +" +...+%&+ ", +" %*=-*&;$=&* ", +" %**=$@;>@=&*% ", +" &**@$*@@$-.+& ", +" %$%@*..$@.. ", +" ,#@+++@@#& ", +" $,#$$@@$#=$'' ", +" )!!!~!{=],,,,]^)'!{') =/, ", +" )){'~!!'')=],=))'{)'')) /=],( ", +" )'!!'!)~'{'),)''''''')) @@/==](( ", +" ^)''')'{{''')'''''),))) $$@$/,( ", +" ,^))),))''''))'')^,__/$$$-#-(( ", +" :<[}<,_)))))))),___,]#@@-/]] ", +" :<|12<:_,,,,,_,#$$-#/,^^=^}}< ", +" :<[1}::,^,,__,#$-==/,,::^:<<< ", +" ::&+@#^,,__/)#-=/,,,,-::^<::= ", +" :*+12[:==_,$-=/,,,,/,#::::=^ ", +" #*}331}-$]-==/,,,,// ##:=^ ", +" /]<13[---],,,,,,,]_] ", +" ,:--/,___]]]]:^___/ ", +" _______,^^,^,__/# ", +" ______:::::/$,,/# ", +" ____^:::=,^^^^,^^ ", +" __,,:=^,,)))^,,= ", +" _,,),,,,,^)^^^,, ", +" ,^,,),__,^))),,^ ", +" ,,,^^,,,,,)))),, ", +" ,,,,,,,)^))))^ ", +" ,,^,,,^^)))))^ ", +" ,^^,,,,)))))), ", +" ,^,,,,))^))), ", +" ],,,,,$&&&*$# ", +" ],,,]#****$# ", +" ]]]]]^####, ", +" ]]]]*,,,,#* ", +" ,_,#@&&@*/ ", +" __$####=# ", +" ,_/$$$$$# ", +" ,,,$*$$$ ", +" ],,,$**$# ", +" ],,,@&&@# ", +" ],,,$**#= ", +" ,,=+++%$ ", +" *%%%*$ ", +" /$*$#/ ", +" ],,]] "}; diff --git a/src/r_draw.h b/src/r_draw.h index c45700a212..fa84e5ae91 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -116,7 +116,6 @@ extern void (*R_DrawSpanMaskedAddClamp)(void); // [RH] Span blit into an interleaved intermediate buffer extern void (*R_DrawColumnHoriz)(void); -void R_DrawMaskedColumnHoriz (const BYTE *column, const FTexture::Span *spans); // [RH] Initialize the above pointers void R_InitColumnDrawers (); @@ -183,6 +182,7 @@ extern void (*rt_map4cols)(int sx, int yl, int yh); #define rt_addclamp4cols rt_addclamp4cols_c #endif +void rt_flip_posts(); void rt_draw4cols (int sx); // [RH] Preps the temporary horizontal buffer. diff --git a/src/r_drawt.cpp b/src/r_drawt.cpp index e8faff0ceb..cb228cce05 100644 --- a/src/r_drawt.cpp +++ b/src/r_drawt.cpp @@ -838,6 +838,21 @@ void rt_tlaterevsubclamp4cols (int sx, int yl, int yh) rt_revsubclamp4cols(sx, yl, yh); } +// Reorder the posts so that they get drawn top-to-bottom instead of bottom-to-top. +void rt_flip_posts() +{ + unsigned int *front = horizspan[dc_x & 3]; + unsigned int *back = dc_ctspan[dc_x & 3] - 2; + + while (front < back) + { + swapvalues(front[0], back[0]); + swapvalues(front[1], back[1]); + front += 2; + back -= 2; + } +} + // Copies all spans in all four columns to the screen starting at sx. // sx should be dword-aligned. void rt_draw4cols (int sx) @@ -1103,101 +1118,3 @@ void R_FillColumnHorizP (void) dest += 8; } while (--count); } - -// Same as R_DrawMaskedColumn() except that it always uses R_DrawColumnHoriz(). - -void R_DrawMaskedColumnHoriz (const BYTE *column, const FTexture::Span *span) -{ - const fixed_t texturemid = FLOAT2FIXED(dc_texturemid); - while (span->Length != 0) - { - const int length = span->Length; - const int top = span->TopOffset; - - // calculate unclipped screen coordinates for post - dc_yl = xs_RoundToInt(sprtopscreen + spryscale * top); - dc_yh = xs_RoundToInt(sprtopscreen + spryscale * (top + length) - 1); - - if (sprflipvert) - { - swapvalues (dc_yl, dc_yh); - } - - if (dc_yh >= mfloorclip[dc_x]) - { - dc_yh = mfloorclip[dc_x] - 1; - } - if (dc_yl < mceilingclip[dc_x]) - { - dc_yl = mceilingclip[dc_x]; - } - - if (dc_yl <= dc_yh) - { - if (sprflipvert) - { - dc_texturefrac = (dc_yl*dc_iscale) - (top << FRACBITS) - - fixed_t(CenterY * dc_iscale) - texturemid; - const fixed_t maxfrac = length << FRACBITS; - while (dc_texturefrac >= maxfrac) - { - if (++dc_yl > dc_yh) - goto nextpost; - dc_texturefrac += dc_iscale; - } - fixed_t endfrac = dc_texturefrac + (dc_yh-dc_yl)*dc_iscale; - while (endfrac < 0) - { - if (--dc_yh < dc_yl) - goto nextpost; - endfrac -= dc_iscale; - } - } - else - { - dc_texturefrac = texturemid - (top << FRACBITS) - + (dc_yl*dc_iscale) - fixed_t((CenterY-1) * dc_iscale); - while (dc_texturefrac < 0) - { - if (++dc_yl > dc_yh) - goto nextpost; - dc_texturefrac += dc_iscale; - } - fixed_t endfrac = dc_texturefrac + (dc_yh-dc_yl)*dc_iscale; - const fixed_t maxfrac = length << FRACBITS; - if (dc_yh < mfloorclip[dc_x]-1 && endfrac < maxfrac - dc_iscale) - { - dc_yh++; - } - else while (endfrac >= maxfrac) - { - if (--dc_yh < dc_yl) - goto nextpost; - endfrac -= dc_iscale; - } - } - dc_source = column + top; - dc_dest = ylookup[dc_yl] + dc_x + dc_destorg; - dc_count = dc_yh - dc_yl + 1; - hcolfunc_pre (); - } -nextpost: - span++; - } - - if (sprflipvert) - { - unsigned int *front = horizspan[dc_x&3]; - unsigned int *back = dc_ctspan[dc_x&3] - 2; - - // Reorder the posts so that they get drawn top-to-bottom - // instead of bottom-to-top. - while (front < back) - { - swapvalues (front[0], back[0]); - swapvalues (front[1], back[1]); - front += 2; - back -= 2; - } - } -} diff --git a/src/r_main.cpp b/src/r_main.cpp index 4252f4155a..c69c22c7ba 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -355,7 +355,7 @@ void R_SWRSetWindow(int windowSize, int fullWidth, int fullHeight, int stHeight, MaxVisForWall = (InvZtoScale * (SCREENWIDTH*r_Yaspect) / (viewwidth*SCREENHEIGHT * FocalTangent)); MaxVisForWall = 32767.0 / MaxVisForWall; - MaxVisForFloor = 32767.0 / (viewheight * FocalLengthY / 160); + MaxVisForFloor = 32767.0 / (viewheight >> 2) * FocalLengthY / 160; // Reset r_*Visibility vars R_SetVisibility(R_GetVisibility()); diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 07efb84b4d..810aa0003c 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -221,10 +221,26 @@ void R_MapPlane (int y, int x1) distance = planeheight * yslope[y]; - ds_xstep = xs_ToFixed(32-ds_xbits, distance * xstepscale); - ds_ystep = xs_ToFixed(32-ds_ybits, distance * ystepscale); - ds_xfrac = xs_ToFixed(32-ds_xbits, distance * basexfrac) + pviewx; - ds_yfrac = xs_ToFixed(32-ds_ybits, distance * baseyfrac) + pviewy; + if (ds_xbits != 0) + { + ds_xstep = xs_ToFixed(32 - ds_xbits, distance * xstepscale); + ds_xfrac = xs_ToFixed(32 - ds_xbits, distance * basexfrac) + pviewx; + } + else + { + ds_xstep = 0; + ds_xfrac = 0; + } + if (ds_ybits != 0) + { + ds_ystep = xs_ToFixed(32 - ds_ybits, distance * ystepscale); + ds_yfrac = xs_ToFixed(32 - ds_ybits, distance * baseyfrac) + pviewy; + } + else + { + ds_ystep = 0; + ds_yfrac = 0; + } if (plane_shade) { @@ -357,7 +373,7 @@ void R_CalcTiltedLighting (double lval, double lend, int width) // //========================================================================== -void R_MapTiltedPlane (int y, int x1) +void R_MapTiltedPlane(int y, int x1) { int x2 = spanend[y]; int width = x2 - x1; @@ -366,18 +382,18 @@ void R_MapTiltedPlane (int y, int x1) DWORD u, v; int i; - iz = plane_sz[2] + plane_sz[1]*(centery-y) + plane_sz[0]*(x1-centerx); + iz = plane_sz[2] + plane_sz[1] * (centery - y) + plane_sz[0] * (x1 - centerx); // Lighting is simple. It's just linear interpolation from start to end if (plane_shade) { - uz = (iz + plane_sz[0]*width) * planelightfloat; + uz = (iz + plane_sz[0] * width) * planelightfloat; vz = iz * planelightfloat; - R_CalcTiltedLighting (vz, uz, width); + R_CalcTiltedLighting(vz, uz, width); } - uz = plane_su[2] + plane_su[1]*(centery-y) + plane_su[0]*(x1-centerx); - vz = plane_sv[2] + plane_sv[1]*(centery-y) + plane_sv[0]*(x1-centerx); + uz = plane_su[2] + plane_su[1] * (centery - y) + plane_su[0] * (x1 - centerx); + vz = plane_sv[2] + plane_sv[1] * (centery - y) + plane_sv[0] * (x1 - centerx); fb = ylookup[y] + x1 + dc_destorg; @@ -595,9 +611,10 @@ visplane_t *R_FindPlane (const secplane_t &height, FTextureID picnum, int lightl fixed_t alpha = FLOAT2FIXED(Alpha); //angle_t angle = (xform.Angle + xform.baseAngle).BAMs(); + FTransform nulltransform; + if (picnum == skyflatnum) // killough 10/98 { // most skies map together - FTransform nulltransform; lightlevel = 0; xform = &nulltransform; nulltransform.xOffs = nulltransform.yOffs = nulltransform.baseyOffs = 0; @@ -1887,6 +1904,15 @@ void R_DrawTiltedPlane (visplane_t *pl, double _xscale, double _yscale, fixed_t } } + // Hack in support for 1 x Z and Z x 1 texture sizes + if (ds_ybits == 0) + { + plane_sv[2] = plane_sv[1] = plane_sv[0] = 0; + } + if (ds_xbits == 0) + { + plane_su[2] = plane_su[1] = plane_su[0] = 0; + } #if defined(X86_ASM) if (ds_source != ds_curtiltedsource) R_SetTiltedSpanSource_ASM (ds_source); diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 48d8f1651a..45e3044d3a 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -173,7 +173,7 @@ CVAR(Bool, r_drawmirrors, true, 0) float *MaskedSWall; float MaskedScaleY; -static void BlastMaskedColumn (void (*blastfunc)(const BYTE *pixels, const FTexture::Span *spans), FTexture *tex) +static void BlastMaskedColumn (FTexture *tex, bool useRt) { // calculate lighting if (fixedcolormap == NULL && fixedlightlev < 0) @@ -198,7 +198,7 @@ static void BlastMaskedColumn (void (*blastfunc)(const BYTE *pixels, const FText // draw the texture const FTexture::Span *spans; const BYTE *pixels = tex->GetColumn (maskedtexturecol[dc_x] >> FRACBITS, &spans); - blastfunc (pixels, spans); + R_DrawMaskedColumn(pixels, spans, useRt); rw_light += rw_lightstep; spryscale += rw_scalestep; } @@ -441,7 +441,7 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2) { for (dc_x = x1; dc_x < x2; ++dc_x) { - BlastMaskedColumn (R_DrawMaskedColumn, tex); + BlastMaskedColumn (tex, false); } } else @@ -456,24 +456,24 @@ void R_RenderMaskedSegRange (drawseg_t *ds, int x1, int x2) while ((dc_x < stop) && (dc_x & 3)) { - BlastMaskedColumn (R_DrawMaskedColumn, tex); + BlastMaskedColumn (tex, false); dc_x++; } while (dc_x < stop) { rt_initcols(); - BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex); dc_x++; - BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex); dc_x++; - BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex); dc_x++; - BlastMaskedColumn (R_DrawMaskedColumnHoriz, tex); + BlastMaskedColumn (tex, true); dc_x++; + BlastMaskedColumn (tex, true); dc_x++; + BlastMaskedColumn (tex, true); dc_x++; + BlastMaskedColumn (tex, true); rt_draw4cols (dc_x - 3); dc_x++; } while (dc_x < x2) { - BlastMaskedColumn (R_DrawMaskedColumn, tex); + BlastMaskedColumn (tex, false); dc_x++; } } @@ -1104,6 +1104,12 @@ void wallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *l rw_pic->GetHeight(); // Make sure texture size is loaded fracbits = 32 - rw_pic->HeightBits; + if (fracbits == 32) + { // Hack for one pixel tall textures + fracbits = 0; + yrepeat = 0; + dc_texturemid = 0; + } setupvline(fracbits); xoffset = rw_offset; basecolormapdata = basecolormap->Maps; @@ -1456,6 +1462,12 @@ void maskwallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_ rw_pic->GetHeight(); // Make sure texture size is loaded fracbits = 32- rw_pic->HeightBits; + if (fracbits == 32) + { // Hack for one pixel tall textures + fracbits = 0; + yrepeat = 0; + dc_texturemid = 0; + } setupmvline(fracbits); xoffset = rw_offset; basecolormapdata = basecolormap->Maps; @@ -1631,6 +1643,12 @@ void transmaskwallscan (int x1, int x2, short *uwal, short *dwal, float *swal, f rw_pic->GetHeight(); // Make sure texture size is loaded fracbits = 32 - rw_pic->HeightBits; + if (fracbits == 32) + { // Hack for one pixel tall textures + fracbits = 0; + yrepeat = 0; + dc_texturemid = 0; + } setuptmvline(fracbits); xoffset = rw_offset; basecolormapdata = basecolormap->Maps; @@ -2521,7 +2539,7 @@ void R_StoreWallRange (int start, int stop) lwal = (fixed_t *)(openings + ds_p->maskedtexturecol); swal = (float *)(openings + ds_p->swall); FTexture *pic = TexMan(sidedef->GetTexture(side_t::mid), true); - double yscale = pic->Scale.X * sidedef->GetTextureYScale(side_t::mid); + double yscale = pic->Scale.Y * sidedef->GetTextureYScale(side_t::mid); fixed_t xoffset = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::mid)); if (pic->bWorldPanning) @@ -3245,7 +3263,7 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper, { // calculate lighting dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, wallshade) << COLORMAPSHIFT); } - R_WallSpriteColumn (R_DrawMaskedColumn); + R_WallSpriteColumn (false); dc_x++; } @@ -3258,7 +3276,7 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper, rt_initcols(); for (int zz = 4; zz; --zz) { - R_WallSpriteColumn (R_DrawMaskedColumnHoriz); + R_WallSpriteColumn (true); dc_x++; } rt_draw4cols (dc_x - 4); @@ -3270,7 +3288,7 @@ static void R_RenderDecal (side_t *wall, DBaseDecal *decal, drawseg_t *clipper, { // calculate lighting dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, wallshade) << COLORMAPSHIFT); } - R_WallSpriteColumn (R_DrawMaskedColumn); + R_WallSpriteColumn (false); dc_x++; } } diff --git a/src/r_things.cpp b/src/r_things.cpp index a886244431..cad434fa5c 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -250,18 +250,16 @@ double sprtopscreen; bool sprflipvert; -void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *span) +void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *span, bool useRt) { - const fixed_t centeryfrac = FLOAT2FIXED(CenterY); - const fixed_t texturemid = FLOAT2FIXED(dc_texturemid); while (span->Length != 0) { const int length = span->Length; const int top = span->TopOffset; // calculate unclipped screen coordinates for post - dc_yl = xs_RoundToInt(sprtopscreen + spryscale * top); - dc_yh = xs_RoundToInt(sprtopscreen + spryscale * (top + length)) - 1; + dc_yl = (int)(sprtopscreen + spryscale * top + 0.5); + dc_yh = (int)(sprtopscreen + spryscale * (top + length) + 0.5) - 1; if (sprflipvert) { @@ -279,56 +277,20 @@ void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *span) if (dc_yl <= dc_yh) { - if (sprflipvert) - { - dc_texturefrac = (dc_yl*dc_iscale) - (top << FRACBITS) - - FixedMul (centeryfrac, dc_iscale) - texturemid; - const fixed_t maxfrac = length << FRACBITS; - while (dc_texturefrac >= maxfrac) - { - if (++dc_yl > dc_yh) - goto nextpost; - dc_texturefrac += dc_iscale; - } - fixed_t endfrac = dc_texturefrac + (dc_yh-dc_yl)*dc_iscale; - while (endfrac < 0) - { - if (--dc_yh < dc_yl) - goto nextpost; - endfrac -= dc_iscale; - } - } - else - { - dc_texturefrac = texturemid - (top << FRACBITS) - + (dc_yl*dc_iscale) - FixedMul (centeryfrac-FRACUNIT, dc_iscale); - while (dc_texturefrac < 0) - { - if (++dc_yl > dc_yh) - goto nextpost; - dc_texturefrac += dc_iscale; - } - fixed_t endfrac = dc_texturefrac + (dc_yh-dc_yl)*dc_iscale; - const fixed_t maxfrac = length << FRACBITS; - if (dc_yh < mfloorclip[dc_x]-1 && endfrac < maxfrac - dc_iscale) - { - dc_yh++; - } - else while (endfrac >= maxfrac) - { - if (--dc_yh < dc_yl) - goto nextpost; - endfrac -= dc_iscale; - } - } - dc_source = column + top; - dc_dest = ylookup[dc_yl] + dc_x + dc_destorg; + dc_texturefrac = FLOAT2FIXED((dc_yl + 0.5 - sprtopscreen) / spryscale); + dc_source = column; + dc_dest = (ylookup[dc_yl] + dc_x) + dc_destorg; dc_count = dc_yh - dc_yl + 1; - colfunc (); + if (useRt) + hcolfunc_pre(); + else + colfunc (); } -nextpost: span++; } + + if (sprflipvert && useRt) + rt_flip_posts(); } // [ZZ] @@ -470,7 +432,7 @@ void R_DrawVisSprite (vissprite_t *vis) { pixels = tex->GetColumn (frac >> FRACBITS, &spans); if (ispsprite || !R_ClipSpriteColumnWithPortals(vis)) - R_DrawMaskedColumn (pixels, spans); + R_DrawMaskedColumn (pixels, spans, false); dc_x++; frac += xiscale; } @@ -482,7 +444,7 @@ void R_DrawVisSprite (vissprite_t *vis) { pixels = tex->GetColumn (frac >> FRACBITS, &spans); if (ispsprite || !R_ClipSpriteColumnWithPortals(vis)) - R_DrawMaskedColumnHoriz (pixels, spans); + R_DrawMaskedColumn (pixels, spans, true); dc_x++; frac += xiscale; } @@ -493,7 +455,7 @@ void R_DrawVisSprite (vissprite_t *vis) { pixels = tex->GetColumn (frac >> FRACBITS, &spans); if (ispsprite || !R_ClipSpriteColumnWithPortals(vis)) - R_DrawMaskedColumn (pixels, spans); + R_DrawMaskedColumn (pixels, spans, false); dc_x++; frac += xiscale; } @@ -603,7 +565,7 @@ void R_DrawWallSprite(vissprite_t *spr) dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, shade) << COLORMAPSHIFT); } if (!R_ClipSpriteColumnWithPortals(spr)) - R_WallSpriteColumn(R_DrawMaskedColumn); + R_WallSpriteColumn(false); dc_x++; } @@ -617,7 +579,7 @@ void R_DrawWallSprite(vissprite_t *spr) for (int zz = 4; zz; --zz) { if (!R_ClipSpriteColumnWithPortals(spr)) - R_WallSpriteColumn(R_DrawMaskedColumnHoriz); + R_WallSpriteColumn(true); dc_x++; } rt_draw4cols(dc_x - 4); @@ -630,14 +592,14 @@ void R_DrawWallSprite(vissprite_t *spr) dc_colormap = usecolormap->Maps + (GETPALOOKUP (rw_light, shade) << COLORMAPSHIFT); } if (!R_ClipSpriteColumnWithPortals(spr)) - R_WallSpriteColumn(R_DrawMaskedColumn); + R_WallSpriteColumn(false); dc_x++; } } R_FinishSetPatchStyle(); } -void R_WallSpriteColumn (void (*drawfunc)(const BYTE *column, const FTexture::Span *spans)) +void R_WallSpriteColumn (bool useRt) { float iscale = swall[dc_x] * MaskedScaleY; dc_iscale = FLOAT2FIXED(iscale); @@ -651,7 +613,7 @@ void R_WallSpriteColumn (void (*drawfunc)(const BYTE *column, const FTexture::Sp const FTexture::Span *spans; column = WallSpriteTile->GetColumn (lwall[dc_x] >> FRACBITS, &spans); dc_texturefrac = 0; - drawfunc (column, spans); + R_DrawMaskedColumn(column, spans, useRt); rw_light += rw_lightstep; } @@ -984,21 +946,23 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor const double thingxscalemul = spriteScale.X / tex->Scale.X; tx -= ((renderflags & RF_XFLIP) ? (tex->GetWidth() - tex->LeftOffset - 1) : tex->LeftOffset) * thingxscalemul; - x1 = centerx + xs_RoundToInt(tx * xscale); + double dtx1 = tx * xscale; + x1 = centerx + xs_RoundToInt(dtx1); // off the right side? if (x1 >= WindowRight) return; tx += tex->GetWidth() * thingxscalemul; - x2 = centerx + xs_RoundToInt(tx * xscale); + double dtx2 = tx * xscale; + x2 = centerx + xs_RoundToInt(dtx2); // off the left side or too small? if ((x2 < WindowLeft || x2 <= x1)) return; xscale = spriteScale.X * xscale / tex->Scale.X; - iscale = (tex->GetWidth() << FRACBITS) / (x2 - x1); + iscale = (fixed_t)(tex->GetWidth() / (dtx2 - dtx1) * FRACUNIT); double yscale = spriteScale.Y / tex->Scale.Y; @@ -1026,8 +990,7 @@ void R_ProjectSprite (AActor *thing, int fakeside, F3DFloor *fakefloor, F3DFloor vis->xiscale = iscale; } - if (vis->x1 > x1) - vis->startfrac += vis->xiscale * (vis->x1 - x1); + vis->startfrac += (fixed_t)(vis->xiscale * (vis->x1 - centerx - dtx1 + 0.5 * thingxscalemul)); } else { @@ -1339,7 +1302,7 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double } sx = pspr->oldx + (pspr->x - pspr->oldx) * ticfrac; - sy = pspr->oldy + (pspr->y - pspr->oldy) * ticfrac; + sy = pspr->oldy + (pspr->y - pspr->oldy) * ticfrac + WEAPON_FUDGE_Y; if (pspr->Flags & PSPF_ADDBOB) { @@ -1647,7 +1610,7 @@ void R_DrawPlayerSprites () else { wx = weapon->oldx + (weapon->x - weapon->oldx) * r_TicFracF; - wy = weapon->oldy + (weapon->y - weapon->oldy) * r_TicFracF; + wy = weapon->oldy + (weapon->y - weapon->oldy) * r_TicFracF + WEAPON_FUDGE_Y; } } else diff --git a/src/r_things.h b/src/r_things.h index 29e69d3a56..53b887b181 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -124,8 +124,8 @@ extern double pspriteyscale; extern FTexture *WallSpriteTile; -void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *spans); -void R_WallSpriteColumn (void (*drawfunc)(const BYTE *column, const FTexture::Span *spans)); +void R_DrawMaskedColumn (const BYTE *column, const FTexture::Span *spans, bool useRt); +void R_WallSpriteColumn (bool useRt); void R_CacheSprite (spritedef_t *sprite); void R_SortVisSprites (int (*compare)(const void *, const void *), size_t first); diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 524b121756..a51a7101be 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1301,6 +1301,32 @@ void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, fl S_StartSound (NULL, sec, NULL, NULL, channel, sfxid, volume, attenuation); } +//========================================================================== +// +// S_PlaySound - Subfunction used by ACS and DECORATE +// +// Has a local parameter to make the sound audible only to the source +// +//========================================================================== + +void S_PlaySound(AActor *a, int chan, FSoundID sid, float vol, float atten, bool local) +{ + if (a == nullptr) + return; + + if (!local) + { + S_Sound(a, chan, sid, vol, atten); + } + else + { + if (a->CheckLocalView(consoleplayer)) + { + S_Sound(chan, sid, vol, ATTN_NONE); + } + } +} + //========================================================================== // // S_LoadSound diff --git a/src/s_sound.h b/src/s_sound.h index 9b917e25c8..d6d2a5403e 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -241,6 +241,9 @@ void S_Sound (const FPolyObj *poly, int channel, FSoundID sfxid, float volume, f void S_Sound (const sector_t *sec, int channel, FSoundID sfxid, float volume, float attenuation); void S_Sound(const DVector3 &pos, int channel, FSoundID sfxid, float volume, float attenuation); +// [Nash] Used by ACS and DECORATE +void S_PlaySound(AActor *a, int chan, FSoundID sid, float vol, float atten, bool local); + // sound channels // channel 0 never willingly overrides // other channels (1-7) always override a playing sound on that channel diff --git a/src/serializer.cpp b/src/serializer.cpp index 49226ce801..dec81e86fe 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -67,6 +67,143 @@ char nulspace[1024 * 1024 * 4]; bool save_full = false; // for testing. Should be removed afterward. +int utf8_encode(int32_t codepoint, char *buffer, int *size) +{ + if (codepoint < 0) + return -1; + else if (codepoint < 0x80) + { + buffer[0] = (char)codepoint; + *size = 1; + } + else if (codepoint < 0x800) + { + buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6); + buffer[1] = 0x80 + ((codepoint & 0x03F)); + *size = 2; + } + else if (codepoint < 0x10000) + { + buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12); + buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6); + buffer[2] = 0x80 + ((codepoint & 0x003F)); + *size = 3; + } + else if (codepoint <= 0x10FFFF) + { + buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18); + buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12); + buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6); + buffer[3] = 0x80 + ((codepoint & 0x00003F)); + *size = 4; + } + else + return -1; + + return 0; +} + +int utf8_decode(const char *src, int *size) +{ + int c = src[0] & 255; + int r; + + *size = 1; + if ((c & 0x80) == 0) + { + return c; + } + + int c1 = src[1] & 255; + + if ((c & 0xE0) == 0xC0) + { + r = ((c & 0x1F) << 6) | c1; + if (r >= 128) + { + *size = 2; + return r; + } + return -1; + } + + int c2 = src[2] & 255; + + if ((c & 0xF0) == 0xE0) + { + r = ((c & 0x0F) << 12) | (c1 << 6) | c2; + if (r >= 2048 && (r < 55296 || r > 57343)) + { + *size = 3; + return r; + } + return -1; + } + + int c3 = src[3] & 255; + + if ((c & 0xF8) == 0xF0) + { + r = ((c & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3; + if (r >= 65536 && r <= 1114111) + { + *size = 4; + return r; + } + } + return -1; +} + +static TArray out; +static const char *StringToUnicode(const char *cc, int size = -1) +{ + int ch; + const char *c = cc; + int count = 0; + int count1 = 0; + out.Clear(); + while (ch = (*c++) & 255) + { + count1++; + if (ch >= 128) + { + if (ch < 0x800) count += 2; + else count += 3; + // The source cannot contain 4-byte chars. + } + else count++; + if (count1 == size && size > 0) break; + } + if (count == count1) return cc; // string is pure ASCII. + // we need to convert + out.Resize(count + 1); + out.Last() = 0; + c = cc; + int i = 0; + while (ch = (*c++) & 255) + { + utf8_encode(ch, &out[i], &count1); + i += count1; + } + return &out[0]; +} + +static const char *UnicodeToString(const char *cc) +{ + out.Resize((unsigned)strlen(cc) + 1); + int ndx = 0; + while (*cc != 0) + { + int size; + int c = utf8_decode(cc, &size); + if (c < 0 || c > 255) c = '?'; + out[ndx++] = c; + cc += size; + } + out[ndx] = 0; + return &out[0]; +} + //========================================================================== // // @@ -99,8 +236,8 @@ struct FJSONObject struct FWriter { - typedef rapidjson::Writer > Writer; - typedef rapidjson::PrettyWriter > PrettyWriter; + typedef rapidjson::Writer > Writer; + typedef rapidjson::PrettyWriter > PrettyWriter; Writer *mWriter1; PrettyWriter *mWriter2; @@ -173,14 +310,16 @@ struct FWriter void String(const char *k) { + k = StringToUnicode(k); if (mWriter1) mWriter1->String(k); else if (mWriter2) mWriter2->String(k); } void String(const char *k, int size) { - if (mWriter1) mWriter1->String(k, size); - else if (mWriter2) mWriter2->String(k, size); + k = StringToUnicode(k, size); + if (mWriter1) mWriter1->String(k); + else if (mWriter2) mWriter2->String(k); } void Bool(bool k) @@ -602,7 +741,7 @@ FSerializer &FSerializer::Args(const char *key, int *args, int *defargs, int spe } else if (i == 0 && aval.IsString()) { - args[i] = -FName(aval.GetString()); + args[i] = -FName(UnicodeToString(aval.GetString())); } else { @@ -654,7 +793,7 @@ FSerializer &FSerializer::ScriptNum(const char *key, int &num) } else if (val->IsString()) { - num = -FName(val->GetString()); + num = -FName(UnicodeToString(val->GetString())); } else { @@ -709,7 +848,7 @@ FSerializer &FSerializer::Sprite(const char *key, int32_t &spritenum, int32_t *d { if (val->IsString()) { - uint32_t name = *reinterpret_cast(val->GetString()); + uint32_t name = *reinterpret_cast(UnicodeToString(val->GetString())); for (auto hint = NumStdSprites; hint-- != 0; ) { if (sprites[hint].dwName == name) @@ -747,7 +886,7 @@ FSerializer &FSerializer::StringPtr(const char *key, const char *&charptr) { if (val->IsString()) { - charptr = val->GetString(); + charptr = UnicodeToString(val->GetString()); } else { @@ -1403,7 +1542,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTe assert(nameval.IsString() && typeval.IsInt()); if (nameval.IsString() && typeval.IsInt()) { - value = TexMan.GetTexture(nameval.GetString(), typeval.GetInt()); + value = TexMan.GetTexture(UnicodeToString(nameval.GetString()), typeval.GetInt()); } else { @@ -1553,7 +1692,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *d assert(val->IsString()); if (val->IsString()) { - value = val->GetString(); + value = UnicodeToString(val->GetString()); } else { @@ -1638,7 +1777,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundI assert(val->IsString() || val->IsNull()); if (val->IsString()) { - sid = val->GetString(); + sid = UnicodeToString(val->GetString()); } else if (val->IsNull()) { @@ -1687,7 +1826,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClassActor assert(val->IsString() || val->IsNull()); if (val->IsString()) { - clst = PClass::FindActor(val->GetString()); + clst = PClass::FindActor(UnicodeToString(val->GetString())); } else if (val->IsNull()) { @@ -1735,7 +1874,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClass *&cl { if (val->IsString()) { - clst = PClass::FindClass(val->GetString()); + clst = PClass::FindClass(UnicodeToString(val->GetString())); } else if (val->IsNull()) { @@ -1810,7 +1949,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState assert(cls.IsString() && ndx.IsUint()); if (cls.IsString() && ndx.IsUint()) { - PClassActor *clas = PClass::FindActor(cls.GetString()); + PClassActor *clas = PClass::FindActor(UnicodeToString(cls.GetString())); if (clas && ndx.GetUint() < (unsigned)clas->NumOwnedStates) { state = clas->OwnedStates + ndx.GetUint(); @@ -1932,7 +2071,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FString *&p } else if (val->IsString()) { - pstr = AActor::mStringPropertyData.Alloc(val->GetString()); + pstr = AActor::mStringPropertyData.Alloc(UnicodeToString(val->GetString())); } else { @@ -1974,7 +2113,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FString &pstr, FString } else if (val->IsString()) { - pstr = val->GetString(); + pstr = UnicodeToString(val->GetString()); } else { @@ -2023,7 +2162,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr } else if (val->IsString()) { - pstr = copystring(val->GetString()); + pstr = copystring(UnicodeToString(val->GetString())); } else { diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp index 760437db99..9c1b5fdb42 100644 --- a/src/textures/texture.cpp +++ b/src/textures/texture.cpp @@ -210,8 +210,9 @@ void FTexture::CalcBitSize () } WidthMask = (1 << WidthBits) - 1; - // The minimum height is 2, because we cannot shift right 32 bits. - for (i = 1; (1 << i) < Height; ++i) + //
The minimum height is 2, because we cannot shift right 32 bits. + // Scratch that. Somebody actually made a 1x1 texture, so now we have to handle it. + for (i = 0; (1 << i) < Height; ++i) { } HeightBits = i; diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 4677c4b087..bef7328944 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -299,7 +299,7 @@ void DCanvas::DrawTextureParms(FTexture *img, DrawParms &parms) while ((dc_x < stop4) && (dc_x & 3)) { pixels = img->GetColumn(frac >> FRACBITS, spanptr); - R_DrawMaskedColumn(pixels, spans); + R_DrawMaskedColumn(pixels, spans, false); dc_x++; frac += xiscale_i; } @@ -310,7 +310,7 @@ void DCanvas::DrawTextureParms(FTexture *img, DrawParms &parms) for (int zz = 4; zz; --zz) { pixels = img->GetColumn(frac >> FRACBITS, spanptr); - R_DrawMaskedColumnHoriz(pixels, spans); + R_DrawMaskedColumn(pixels, spans, true); dc_x++; frac += xiscale_i; } @@ -320,7 +320,7 @@ void DCanvas::DrawTextureParms(FTexture *img, DrawParms &parms) while (dc_x < x2_i) { pixels = img->GetColumn(frac >> FRACBITS, spanptr); - R_DrawMaskedColumn(pixels, spans); + R_DrawMaskedColumn(pixels, spans, false); dc_x++; frac += xiscale_i; } @@ -1330,6 +1330,13 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, return; } + BYTE *destorgsave = dc_destorg; + dc_destorg = screen->GetBuffer(); + if (dc_destorg == NULL) + { + I_FatalError("Attempt to write to buffer of hardware canvas"); + } + scalex /= tex->Scale.X; scaley /= tex->Scale.Y; @@ -1432,6 +1439,7 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, pt1 = pt2; pt2--; if (pt2 < 0) pt2 = npoints; } while (pt1 != botpt); + dc_destorg = destorgsave; #endif } diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 06bfa05691..8bb680dbda 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -1092,6 +1092,7 @@ void D3DFB::Update () DrawRateStuff(); DrawPackedTextures(d3d_showpacks); EndBatch(); // Make sure all batched primitives are drawn. + In2D = 0; Flip(); } In2D = 0; diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index eecc843d39..71e82f613d 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -191,7 +191,7 @@ ACTOR Actor native //: Thinker action native A_ComboAttack(); action native A_BulletAttack(); action native A_WolfAttack(int flags = 0, sound whattoplay = "weapons/pistol", float snipe = 1.0, int maxdamage = 64, int blocksize = 128, int pointblank = 2, int longrange = 4, float runspeed = 160.0, class pufftype = "BulletPuff"); - action native A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, float volume = 1.0, bool looping = false, float attenuation = ATTN_NORM); + action native A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, float volume = 1.0, bool looping = false, float attenuation = ATTN_NORM, bool local = false); native void A_PlayWeaponSound(sound whattoplay); action native A_FLoopActiveSound(); action native A_LoopActiveSound(); diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 658e729da3..d66f785591 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -681,8 +681,8 @@ OptionMenu "VideoOptions" Option "$DSPLYMNU_VSYNC", "vid_vsync", "OnOff" Option "$DSPLYMNU_CAPFPS", "cl_capfps", "OffOn" - Slider "$DSPLYMNU_BLOODFADE", "blood_fade_scalar", 0.0, 1.0, 0.05, 1 - Slider "$DSPLYMNU_PICKUPFADE", "pickup_fade_scalar", 0.0, 1.0, 0.05, 1 + Slider "$DSPLYMNU_BLOODFADE", "blood_fade_scalar", 0.0, 1.0, 0.05, 2 + Slider "$DSPLYMNU_PICKUPFADE", "pickup_fade_scalar", 0.0, 1.0, 0.05, 2 Option "$DSPLYMNU_COLUMNMETHOD", "r_columnmethod", "ColumnMethods" StaticText " " @@ -714,7 +714,7 @@ OptionMenu "VideoOptions" ColorPicker "$DSPLYMNU_DIMCOLOR", "dimcolor" Slider "$DSPLYMNU_MOVEBOB", "movebob", 0, 1.0, 0.05, 2 Slider "$DSPLYMNU_STILLBOB", "stillbob", 0, 1.0, 0.05, 2 - Slider "$DSPLYMNU_BOBSPEED", "wbobspeed", 0, 2.0, 0.1, 2 + Slider "$DSPLYMNU_BOBSPEED", "wbobspeed", 0, 2.0, 0.1 } @@ -1256,7 +1256,7 @@ OptionMenu GameplayOptions Title "$GMPLYMNU_TITLE" //Indent 222 Option "$GMPLYMNU_TEAMPLAY", "teamplay", "OnOff" - Slider "$GMPLYMNU_TEAMDAMAGE", "teamdamage", 0, 1, 0.05 + Slider "$GMPLYMNU_TEAMDAMAGE", "teamdamage", 0, 1, 0.05,2 StaticText " " Option "$GMPLYMNU_SMARTAUTOAIM", "sv_smartaim", "SmartAim" StaticText " " @@ -1806,7 +1806,7 @@ OptionMenu NetworkOptions StaticText "$NETMNU_LOCALOPTIONS", 1 Option "$NETMNU_MOVEPREDICTION", "cl_noprediction", "OffOn" Option "$NETMNU_LINESPECIALPREDICTION", "cl_predict_specials", "OnOff" - Slider "$NETMNU_PREDICTIONLERPSCALE", "cl_predict_lerpscale", 0.0, 0.5, 0.05 + Slider "$NETMNU_PREDICTIONLERPSCALE", "cl_predict_lerpscale", 0.0, 0.5, 0.05, 2 Slider "$NETMNU_LERPTHRESHOLD", "cl_predict_lerpthreshold", 0.1, 16.0, 0.1 StaticText " " StaticText "$NETMNU_HOSTOPTIONS", 1