▶ ICEPICK // OPEN SOURCE · MIT
BUILD YOUR OWN GIG
Everything used to build a working quest mod for Cyberpunk 2077, open on GitHub: the tools, the research notes, and the full source of three shipped side quests to learn from.
// PYTHON GENERATORS · WOLVENKIT · ARCHIVEXL · REDSCRIPT · NO GAME FILES SHIPPED
FROM PYTHON TO NIGHT CITY
Three gigs have come out of this pipeline. Python generators write the quest graph, the scenes, the journal and the map pins as JSON. WolvenKit cooks the JSON into the game's binary formats (.questphase, .scene, .journal, .ent). Everything gets packed into a single archive, and ArchiveXL merges it into the game at launch. The scripts compile with redscript in the player's game.
The generators run dependency-free, and all generated output is committed, so a fresh clone builds without running anything. Every gotcha that cost an evening is written down so it costs you five minutes.
WHAT THE TOOLKIT CAN DO
CAPABILITY 01
Vanilla-grade map pins
Quest pins that route the player there, show the gig icon, and behave exactly like the game's, without shipping a single game file.
CAPABILITY 02
Spawn Johnny and make him glitch
Have Johnny materialize beside the player anywhere in the city, deliver lipsynced lines, and glitch back out. The wiki guide.
CAPABILITY 03
Scenes with dialogue and lipsync
Subtitled conversations with working audio and lipsync. No audio framework, no extra dependencies.
CAPABILITY 04
Phone calls that behave
Calls that ring like the game's own: they wait out fast travel, survive reloads, and try again if you miss them.
CAPABILITY 05
Journal, objectives, payout
A gig that appears in the journal, tracks objectives step by step, and pays out on completion. Indistinguishable from vanilla.
CAPABILITY 06
Borrow the game's own cast
Pull vanilla NPCs like Mama Welles into your scenes and pause their default chatter while your gig talks, or spawn a custom NPC of your own.
CAPABILITY 07
Video holocalls from your own contact
Put a character live on the player's phone, rendered in the game's own holocall studio with their mouth moving, and let the player ring them back. The wiki guide.
CAPABILITY 08
A code grid on a wall box you ship
Breach protocol, the game's own minigame, on an access point your mod puts in a sector of its own. The daemons are named from your own records. The wiki guide.
CAPABILITY 09
A quest area drawn on the minimap
The dotted outline the game draws for its own "leave the area" objectives, drawn for yours, from a trigger area node your mod ships.
CAPABILITY 10
Choices that change the payout
Branch the ending on what the player did. Each outcome goes to the game's own reward routine, so the money notice, the level-scaled XP and the telemetry are vanilla's.
CAPABILITY 11
Turn a whole site on the player
Make every NPC in a compound hostile and aware of V at once, with the four calls the game makes on a MaxTac unit after it lands. Then raise the wanted level from script, tell the responders where the player is every few seconds so leaving the road is no escape, and drop the stars at a line of your choosing.
CAPABILITY 12
A translation kit, made with every build
One WolvenKit project per gig with every string, every invented character's subtitles and a slot for their voices. A translator types over the English, sets a language code and zips. It comes out of the same source as the gig, so an update stays a diff.
UNDER THE HOOD
1. Map pins without shipping a single game file. One way to place a mod-added quest pin is to overwrite Night City's cooked mappin tables. You don't have to. ArchiveXL computes a pin's position from a node reference plus an offset, but the node has to be streamed in when the quest activates the pin, and quests activate pins while you're on the other side of the city. Night City has exactly three sectors the engine never unloads, holding 5,211 globally named nodes between them. Anchor to one of those and the pin just works:
"offset": { "X": 12.4, "Y": -3.1, "Z": 0.5 }
2. Voiced dialogue needs no audio mod. A scene line carries one number, and the game resolves both the subtitle and the audio from it: the words come from a subtitle resource keyed by that number, the voice comes from a locVoiceoverMap keyed by the same one. ArchiveXL merges a mod's entries into both. Gendered V lines are handled by the engine, not by you:
+--> locVoiceoverMap -> the .wem that plays
3. A scene can put a body exactly where you are standing. Lip sync lands on whoever the scene says is speaking, so the scene has to own Johnny's body. For months the playbook here said a scene could not put that body in front of the player: the marker a scene stages an actor on "lands a few metres to one side", and its rotation is "not knowable". A whole architecture was built around that sentence. The speaker was buried under the floor for his voice, a second body was spawned by script, a workspot device lifted it into place, and a 40 m sweep ran six times a second to find it again. The sentence came from one playtest note about how a voice sounded, from an actor who was underground at the time. What it was hearing was the floor. Measured in five runs, the marker sits at V's exact position, carries V's rotation, and +Y is forward:
spawnOffset.orientation = yaw_to_face_player((aside, ahead, 0))
Every workaround above was unnecessary, and the T-pose two Nexus reporters described was a side effect of the workaround rather than of anything the engine forces. Deleting the lot is most of what version 1.2.0 is. A claim that forecloses an approach is worth measuring before it earns a "do not", because a wrong "impossible" costs whatever gets built on top of it, and nobody goes back to re-test it.
4. A video holocall from a contact you invented. A holocall with a live picture is not a video file. The game keeps a hidden set off the map, a "studio", with a camera, lights and a spot for the caller to stand on, and the phone renders whatever that camera sees. Issue the call from the quest graph rather than from script, because the graph's node is the only one carrying the field that aims the phone at the studio:
caller contacts/cc_g01_nix // yours, not the game's Nix
mode Video
prefabNodeRef #holocalls_studio // the only field that aims the feed
The caller has to be a contact you invented. Borrow the game's own Nix and his small-talk conversation takes the call over, so the player gets his default options instead of your scene, and cannot ring out at all. Someone also has to be standing on that spot for the camera to point at, and the game only draws a character in a scene while they are playing an animation. Standing is not one. Put them in a workspot on the scene's first frame or the phone shows an empty room, silently, with nothing in any log.
The lipsync itself ships no animation data at all. Each line borrows a vanilla lipsync animation of roughly the right length, which reads as real sync at conversational distance.
5. The code grid on a wall box you ship yourself. Breach protocol runs on an access point, and an access point is an ordinary device node you can put in a sector of your own. Which one you copy decides whether it works. A quest access point lifted out of the game gives a prompt reading "Install Software" that does nothing, because its saved state carries a personal-link interaction only its own quest ever finishes. Copy one of the street routers instead: their buffer holds the entity and nothing else, so the game builds the default state, which is the one every open-world router runs on. Two more things. The "Jack in" prompt has a volume positioned per appearance, so a box that offers no prompt facing into a room may offer one turned around: place it, then rotate it until the prompt shows. And the list of daemons lives on the controller's saved state, which a node with no saved state cannot carry, so name it from script:
public func SetMinigame(id: TweakDBID) -> Void {
if this.m_minigameDefinition != id { this.m_minigameDefinition = id; }
}
6. A quest area drawn on the minimap. The dotted outline the game draws for its own "leave the area" objectives is not a special kind of pin. It is an ordinary quest map pin whose target happens to be a trigger area node, and the minimap draws the outline while that objective is tracked and the player is standing inside it. 638 of the game's own quest pins point at one. A mod can do the same, but ArchiveXL builds the outline only from a node that is an area shape node: a device node carrying a trigger component gives the pin a position and no outline, and a trigger node the loader can't find gives a marker at the world origin, which reads in game as a marker a kilometre away. It has to be a trigger area node, in one of your own sectors that is always loaded, named in the long form:
outline.buffer // corner count, then X Y Z W per corner in LOCAL space, then height
notifiers questTriggerNotifier_Quest
instance flags // a vanilla trigger area's, not a shard case's
7. The whole site knows where you are, and so does the wanted system. NPCs placed by a community spawn with no particular attitude towards V. Making one hostile and aware of the player's position is the four calls the game makes on each MaxTac unit after it lands: the first two make V an enemy they can see, the third shares V's location, the fourth puts them in combat at once instead of waiting for a detection:
npc.GetSensesComponent().Toggle(true);
TargetTrackingExtension.InjectThreat(npc, player, 1.0, -1.0);
NPCPuppet.ChangeHighLevelState(npc, gamedataNPCHighLevelState.Combat);
The wanted level is a request to the prevention system, the same one the game queues. Heat_0 turns it off again, at whatever place or objective you choose. The responders only know where the player is once one of them has a sighting, so a player who leaves the road can hide. Unless the mod reports the position for them every few seconds, which sets it as the last crime point and hands it to whoever answers, Militech in the Badlands and the NCPD in town:
evt.m_wantedLevel = EPreventionHeatStage.Heat_3;
evt.m_forcePlayerPositionAsLastCrimePoint = true;
preventionSystem.QueueRequest(evt);
// every few seconds, until the player crosses the line you drew
PreventionSystem.CombatStartedRequestToPreventionSystem(game, player);
Acceptable Loss runs all of it: the trace on the security-room door turns the compound, three stars land, and the hunt holds until the district boundary. The gig page has the same notes next to the gig.
WRITTEN FOR THE WIKI
The repo keeps what is specific to these gigs. The general how-to went to the community wiki, where other modders look first and can correct it. Five pages so far, written from scratch by nightcityriot and tested in game on 2.31, each one starting from something that broke while building a gig.
WIKI // QUESTS & SCENES · NEW
Johnny glitching and talking with V
Johnny glitches in a couple of metres in front of V, anywhere in the city, turned to face V, talks in V's head, and glitches out. Without a pose he is invisible: his character hides him until a workspot plays, and he glitches in by himself when it starts. The exit is the part the game skips. The scene ending removes him with no effect, so his glitch has to play 250 ms before the end. Any earlier and he reappears after the flash.
READ ON WIKI.REDMODDING.ORG →WIKI // QUESTS & SCENES
Custom video holocalls
The phone runs the call and an ordinary scene carries the words. Answering alone shows nothing: the call panel and the video open on a separate step. Every phase is drawn as a quest graph, including the time limit that stops a call waiting forever on a studio room that never loads.
READ ON WIKI.REDMODDING.ORG →WIKI // WORLD EDITING · DEVICES
Custom Access Points
Place a vanilla access point with World Builder, put your own daemon on its breach grid and read the result into a quest fact. Also the fix nobody would guess: if the Connect prompt never shows, turn the box 180 degrees. Dead Ringer's pachinko wall is built this way.
READ ON WIKI.REDMODDING.ORG →WIKI // WORLD EDITING · MISC
Apply GameplayRestriction
Switch off driving, sprinting, the phone or a weapon while your scene plays. Some of these are saved with the game: apply VehicleNoInteraction, save, relaunch, and V still can't get into a car. The guide clears your locks at session start so a forgotten one can't strand a player.
READ ON WIKI.REDMODDING.ORG →WIKI // REFERENCE
Reference: GameplayRestriction
All 100 GameplayRestriction records in 2.31, extracted from the game and grouped by what they block. Every name is real. What each one does is confirmed in game for only a handful, and the guide next to it shows how to test the rest.
READ ON WIKI.REDMODDING.ORG →EVERYTHING IS WRITTEN DOWN
The repo holds the reusable builders under tools/questkit/ (scenes, quest graphs, journal entries, map pins, voice, lipsync), the generator scripts, the shared redscript, and the complete source of all three gigs as working examples. The docs cover the fundamentals, how to start a new gig, and the register nobody else keeps: 103 things that cost hours each.
docs/orientation.md
Gig fundamentals: what a gig is made of and how the pieces relate. Read this first.
docs/new-gig.md
Creating a new quest from scratch with the questkit builders.
The gotcha register
Map pins, scenes with lipsync, computer UI, journal systems: the reference notes on how each subsystem actually behaves, including the failures.
mods/gig-01-negative-balance/
The complete source of a shipped quest mod: calls, scenes, guards, a shard, a terminal, an epilogue in a bar.
mods/gig-02-dead-ringer/
The second one, and the newer patterns: a message thread that opens the gig, an access point on a wall, a quest area on the minimap, four endings.
mods/gig-03-acceptable-loss/
The loud one: a compound that turns on the player from script, a forced wanted level held to a district boundary, a choice made in a message thread, and a vanilla fixer on his own barstool. Read it, take what's useful, build your own gig with it, or tell us what we got wrong.
mods/gig-*/translation-kit/
One per gig: the WolvenKit project a translator opens, with every string and every invented character's subtitles, and a README with the steps. Made with every build, from the same source as the gig. The characters the game voices need no translating, because their lines are the game's own and the game ships them in every language.
Bugs in a gig itself are best reported on Nexus; issues with the scripts and docs belong on GitHub. Want to see the result first? Play Acceptable Loss, Dead Ringer or Negative Balance.