News | Forum | People | FAQ | Links | Search | Register | Log in
Copper Quake / Underdark Overbright (UPDATED)
A dual release for Quake's anniversary this weekend:

1. >> Copper Quake, a "Vanilla+" mod that polishes and refines Quake's singleplayer gameplay. It grinds off the roughest edges we've all just gotten used to over the last two decades without moving away from what Quake is at heart, and expands opportunity for high-level play. For example: Nightmare difficulty is an actual playable mode!

Read all the detail about it you desire, and download it, from the Copper site:

2. >> A 7+2 map episode to go with it called Underdark Overbright. It's like czg, sock, and headshot had a sexy baby, featuring guest mapper Scampie!

Download it too:
or ogle screenshots:

UPDATE July 16: new version 1.05 is now available, follow the links above.
First | Previous | Next | Last
Awesome sound, too bad it doesn't get played in END.BSP anyway :(

Who made it and how by the way? 
Lunaran: glad I could be of help. I'm having good nostalgic fun playing through old maps with this mod.

I'm currently working on a QuakeC-based workaround for the "stale entity keys" issue. I've bumped into the same thing in the past, and I'd like to hammer out a decent general-purpose solution to it. I'll share the code when it's finished, will probably get the chance to do that within a day or two. 
What do you have in mind? I'd love to know if there's a more clever way around it than an opt-in "please do it the special new way" selector on worldspawn or something. 
This was a blast and I'm very happy to see it's been well received! Here's my Full playthrough with rambling and commentary
that's just a JPEG 
That's his whole playthrough with commentary, summed up in one picture. 
Thanks for pointing out, here's the correct link for my playthrough: Full playthrough with rambling and commentary 
Sanitizing Entity Fields 
Lunaran: the term "clever way" would probably be too generous. This is an ugly problem, and there doesn't seem to be a silver bullet.

My goal has ended up being to create a single QC file, compat.qc, which could (in theory) be added to any existing mod, and which provides the tools to implement an extremely light "compatibility mode" as painlessly as possible.

Because my target is "any existing mod", I can't assume that the mod's mapping interface can be changed, so an opt-in worldspawn key is a no-go.

I should stress that I do not assume this module is something you will necessarily want to add to Copper. I have simply used Copper as a test case while implementing it. I'm presenting it as something of possible interest.

How it works:


By default, compat.qc will automagically enable the compatibility mode for the stock id1 maps, but not for any other maps. This default behaviour can also be overridden via console commands, allowing a player to play non-stock vanilla maps (which aren't auto-detected) in compatibility mode if they really want to.

It turns out that it's really easy to detect whether one of the stock id1 maps is being played. They all have known file names, so compat.qc checks "world.model" once, on map start, and enables compatibility mode if the file name is one of the stock maps. It's common for mods to provide a "start.bsp" that shadows the stock one (and UDOB does this with "end.bsp" too), but that can be distinguished by checking some other field as well (e.g. "world.message").

This alone makes it feasible to address compatibility with the stock maps, which seems like a big win.

But we've also 20+ years of custom vanilla maps that a player might want to play with whatever mod we're talking about. They can't all be auto-detected.

As a better-than-nothing workaround, compat.qc comes with a config file, compat.cfg, which a mod can load from its quake.rc file. This defines console commands allowing the player to override the default behaviour:

compat_auto: restores the default behaviour.

compat_always: always enables compatibility mode on map start, allowing custom vanilla maps to be played. (This will break maps that are actually made for the mod, and the command warns the player about that, loudly.)

compat_never: always disables compatibility mode on map start. Not really useful for the player, just here for debugging.

Given my self-imposed restriction of "should work with any mod", I think this is the best that can be done, though I'd love to hear of anything better.


compat.qc manages the compatibility mode, but by default, the mode doesn't actually do anything. To make it do things, functions are provided that can be called to sanitize fields (and spawnflags) only if compatibility mode is in effect.

So to fix the func_train problem that affects e3m3 (and e4m4, apparently), only a single line needs to be added near the top of the func_train spawn function:

COMPAT_SanitizeFloat(wait, "wait");

That's it. If compatibility mode is in effect, the "wait" field will be cleared, and a developer message logged. If compatibility mode is not in effect, this is a no-op.


There are equivalent COMPAT_SanitizeVector and COMPAT_SanitizeString functions, and also COMPAT_SanitizeSpawnflag (some entities have rogue spawnflags set).

A mod using this doesn't need to foul up its code with "if/else" wickedness.


Lunaran: as I said above, I do not assume this is something you would definitely want to add to Copper. But if you're curious, a patch implementing this is here:

Changes to existing files are marked with "// iw" comments.

The following things are sanitized when in compatibility mode:

- func_train: "wait" field (affects e3m3, e4m4)

- path_corner: "speed" field (affects "Contract Revoked" maps)

- All non-boss monsters: all new fields and spawnflags (just to demonstrate how easy this becomes)

- In general: the "COOPONLY" and "NOTCOOP" spawnflags (ditto)

In principle, one could go through every spawn function of every stock entity and sanitize every new field and spawnflag that the mod adds, to pre-emptively fix any as-yet-undiscovered problems. I started doing that, but then I realised how many extensions you've added to the stock entities, so I stopped. =) 
Awesome episode. For me it's up there with Zerstörer and a couple of other ones in some kind of unholy pantheon of episodes. From the brilliant startmap to the boss fight, I think it was just about perfect, with a nice arch from "realistic" to gradually more and more abstract level design. But I loved the last two levels as well. Lots of neat surprises and ideas throughout. It's also one of those rare maps/episodes that I restart as soon as I've finished it. For one thing, I have a bunch of secrets to find. Anyway, many thanks for a brilliant episode. 
Yeahh. I've been changing and rearranging code in Copper for a long time. It grew out of the LunSP2 source, which I started right on top of the LunSP1 source, which is from 2003. That's 15 years of "oh this could be cleaner" revisions and "oh I'd like to have this" additions that probably make truly universal compatibility a pipe dream.

Had I started this project from scratch more recently, there might have been more compatibility with progs_dump, but since I started it almost from scratch a long time ago, most of the parity is with Quoth, which was the only big-mapper-feature-add for a long time.

Compatibility isn't limited to just formerly dead spawnflags and keyvalues, either. Very careful mappers would sometimes offset their ammo pickups based on how the models looked, and not the physical bounds of the pickups, and in Copper they'll appear off-center or even z-fight with each other (the ammo in the dapak maps is frequently screwy). Or map hacks: preserving 100% of them was impossible without leaving 100% of the code unchanged, since any free function was eligible to be a notnull's .use(). Does compatibility mode mean maps as hacked as Ascending and Descending work?

There are also already cases where the gameplay changes themselves might soft-break a map, like if Enforcer or Ogre drops were expected to fuel the LG/RL for the entire level.

Just saying "compatibility mode" implies a guarantee that can't be given. :( It's also on the user to remember to be in the right compatibility mode, and it puts these COMPAT_ calls all over the place ... still, this is an impressive patch. I'll give it a think.

I also did not realize Contract Revoked didn't include a progs.dat. this weakens my opinion that it's only critical to support eXmY.bsp, and that the chips can fall where they may everywhere else.

Guess I'm playing Contract in Copper this evening. 
15 Years! 
Wow. I remember playing lunsp1 when it was released, but I hadn't realised it was so long ago!

Considering 15 years of changes, Copper does ... really very well for compatibility. I'm impressed.

Agree 100% that Q1 map-mod compatibility is a bottomless well of absolute despair for all reasons stated.

>>> Or map hacks: preserving 100% of them was impossible without leaving 100% of the code unchanged, since any free function was eligible to be a notnull's .use().

This is so true. I once "harmlessly" refactored barrel_explode and completely broke gmsp3. =(

Nowadays I just assume that maps that use negke-level hacks are a write-off in terms of mod compatibility, exactly because of e.g. info_notnulls calling functions that should be private.

To play new vanilla releases, I use a custom progs.dat which fixes exactly one thing: the Rotfish kill count bug, which I can't cope without. Map hacks have frightened me about compatibility that badly.

>>> Just saying "compatibility mode" implies a guarantee that can't be given. :(

Thanks for pointing this out. Now that you say it ... yeah, I'm inclined to agree. This is a "compatibility mode" to address an *extremely specific* compatibility issue, which is the stale spawnflag/field awfulness. It's not meant to be anything more than that. (My comments at the top of the file make it sound too magical -- gah.)

And yeah, end-user expectations. Right now I have no clue what else to call the module. =( But thanks for the reality check.

BTW, even if my pet idea isn't the way forward: how high a priority is stock engine compatibility? An ent file to patch e3m3 would be ignored by the stock engines.

It's more compatible (if ugly as sin) to include a map-specific hack in the progs. E.g. at the top of func_train:

if (world.model == "maps/e3m3.bsp")
self.wait = 0;

This is so ugly, but it'll work for everyone, even people playing with the WinQuake they downloaded via Steam or whatever. 
That's true. I did advertise that Copper works with any Quake, I guess I can't go back on that now because of one crusher. I gave Copper a try in WinQuake and there was a charming joy to running around in blotchy pixelated 256-color mode again.

Now I have to decide between the abstract badge of honor of being DOSQuake compatible and the abstract badge of honor of not having map-specific hacks in the progs.

A third answer: since all of the problems actually witnessed in the wild seem to stem from func_trains, a Copper-opt-in spawnflag on just func_train is a lot less offensive to my delicate sensibilities. I think I'd only have to update one func_train in all of UDOB (which is going to get an update when Copper does anyway). 
Worldspawn Key 
Lunaran, what's your take on the other possibility, of requiring maps for a mod to self-identify as such by setting a worldspawn key?

This seems tantalizing to me because I could unambiguously distinguish between "a map made for my mod" and "a map not made for my mod", and then switch behaviour (e.g. sanitize certain fields) accordingly.

Just brainstorming:

* It would allow a mod to add a new bugfix even if some terrible backwards-compatibility problem with a specific entity is only discovered far down the road, after people have started releasing maps for the mod, when it wouldn't be possible to add an opt-in key to that specific entity anymore.

* A worldspawn key could be set automatically by a .fgd file (I think?), so it's only the mappers using .def files who would have to remember to set the thing (I think?).

But it sounds like you've already considered this option, so is there a downside I'm overlooking? 
Secret Map? 
*slightly spoilerish*

Replaying the episode, I found the button in udob2 that switches the portal to a ”secret level”, but the level in question is udob7, which of course is part of the episode normally as well. Am I missing something here? 
That's the usual convention of naming secret levels, going back as far as E1M8. 
With a key on worldspawn, we only solve the problem of the player remembering to set the right mode by making the mapper remember instead. It doesn't solve any of the other problems of maintaining two different code paths for everything, which has the potential to be a nightmare of bugs. 
I should have been more clear, I was more thinking about the choice between "key on worldspawn" vs. "key on just func_train" (or whatever affects a given mod) -- both require the mapper to remember something, and both result in two different code paths. Certainly taking advantage of any of these approaches would need to be judicious, and justified in context. Again, I'm thinking generally, and I realise that my own reasons for being interested in these issues aren't really applicable to Copper, so I'll stop rambling about map compatibility and try to get back on-topic.

Having a blast revisiting old vanilla maps with this mod!

* First mod ever to make me think "Oh cool! Another Ring of Shadows!"

* Vores much less tedious to dispatch. There's a sort of a Vore-dance now, where previously there was more of a Vore hide-and-prod.

* Playing the new Nightmare for the first time (UDOB maps), I was constantly on edge about the low health ceiling -- I found myself burning health boxes just to get from e.g. 44 health back up to 50! Been a while since I felt that worried playing Quake.

P.S. on my travels I've come across and squashed some (small, specific, run-of-the mill) bugs -- one is the issue with the "fake" items in e4m2 not showing up, which gila mentioned, and a few other things. Lunaran, I'll aim to send you my findings in an email sometime in the next few days, when I get chance -- don't want to clutter this thread with any more technical stuff than I already have. 
E4M2 fake items: it was the habit Sandy had of using target and killtarget together, so the items thought they were trigger-spawned. Found it, will be fixed in the next version.

When I found out that items with targetnames were problematic (like as the targets of spotlights highlighting them) I should have made it a spawnflag too, to match the monsters, rather than write something silly like SUB_VerifyTriggerable(), but I think I did that in 2010/2011 and never remembered that E4M2 had fake items. :( I was on a 'make everything smart and automatic' kick.

Please, send me the rest of your list! 
Perfect Episode 
Quakecast Interview With Lunaran 
Everyone, here's the newly released Quakecast episode where Dumptruck and I talk to Lunaran:

Quakecast Interview with Lunaran 
maybe I have missed the info somewhere but what are some recommended maps to play with copper quake? I have played the original game and all maps which came with the mod. Need more! 
4 posts not shown on this page because they were spam
First | Previous | Next | Last
You must be logged in to post in this thread.
Website copyright © 2002-2020 John Fitzgibbons. All posts are copyright their respective authors.