Repository navigation
Conversation
The PlayStation 2 release of No One Lives Forever has levels the PC game never had (the three "Nine years ago" flashbacks; a secret basement in "A Man of Influence"). These tools, in build/ps2/, are the start of adding them to the modern build from the player's own PS2 disc; nothing from the disc is committed. - ps2rez.py reads LITH_PS2.REZ: its directory tables and the hash its file names are looked up by. - ps2world.py reads a PS2 world (.ltb, version 66): the PC's BSPs with the PS2's own polygon, lightmap-page and texture data, its static lights and objects. spec-ps2-world.md is the format. - ps2dtx.py turns the PS2's 8-bit palettised textures (BPP_32P) into PC 32-bit textures with mipmaps. - pcworld.py reads and checks a PC world (.dat, version 66), every byte accounted for; spec-pc-world.md is the format, from our engine's loader. - ps2topc.py converts a PS2 world into a PC world: one surface per polygon, texture mapping solved from the PS2 texture coordinates and the PC texture's size (the PC's own, higher-resolution texture wherever one has the name), the PS2's baked lightmaps resampled into PC lightmaps, the lights as Light objects. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ps2model.py reads a PS2 model (.ltb version 16: rigid and skinned
pieces from their VU DMA chains, LODs, skeleton, weight sets, child
models, animations, sockets) and writes a PC model (.abc version 12)
with abcmodel.py, a reader and writer of PC models that rewrites every
.abc of the retail archives byte for byte. spec-models.md is both
formats.
The PS2 keeps names only as hashes, with each model's own multiplier;
they are looked up in a dictionary of candidate names (collect_names:
every name in the PC models, the identifiers in the PS2 executable and
attribute files), collected from the discs and never committed. A
multiplier can be as small as 2, so names collide ("Report" and
"Select" hash the same): the names the game code asks for come first.
A PC vertex weight holds the position in the bone's space times the
weight; the PS2's skinned pieces are converted so. Young Cate's model
(hero_thief) has the PC player's skeleton, so it uses the PC's own
animation models. Checked against PS2 models with PC twins (a hat, a
purse, the lighter): same faces, coordinates, weights and animation.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The PS2 keeps a level's sounds in a bank (lps/<level>.lps) and its voice-over in streams (stream/.../vo_*.lps): one container, a header, 72-byte sound records, a tree of groups that gives each sound its PC path, mono PS-ADPCM data, lip-sync bytes and an SPU preload image. spec-sound.md is the format. ps2sound.py decodes them to 16-bit WAV. ps2soundpc.py finds the sounds the PS2-only levels need that no PC archive has -- from the levels' objects, their dialogue IDs and the PS2 attribute files -- and writes sound-map.txt, the list the installer extracts: the thief levels' 74 lines of dialogue (VOICE\14001-14074), their new events and the safe cracker's sounds. Checked against sounds both releases have: the same length, and in step once the PS2's leading silent frame is skipped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The PS2 string table (LTSR: a count, ID/length/offset records, Latin-1 strings; five languages in the archive) has the text the PS2-only levels use: 103 strings of dialogue, objectives, mission-failed messages, intel texts, the gadgets' names and the loading-screen line. ps2strings.py decodes it and writes it as a resource script, to be compiled into the modern build's CRes.dll at build time (the text is the disc's, so it is generated, never committed, as the Game of the Year text is). 19 of the PS2's IDs are taken on the PC by other text, so they and the gadgets' move into package P8's range, 31700-31799 (ps2-string-map.txt, IDs only); remap_objects rewrites them in a converted level's commands. The rest keep their PS2 IDs, free on the PC: 5326, 6535-6537 and the dialogue's 14001-14074, which name its voice files. src/modern/cres/p8.h names the moved ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What the PS2 release's client does for its "Nine years ago" levels, in the modern build (M-P8-04, M-P8-05): - In a thief level (Worlds\thiefmission*) the loading screen shows "Nine years ago...", the scene of the mission it is played in, and the thief photo, and the first-person hands are young Cate's (guns\skins_pv\ThiefHands_pv.dtx). The PS2 knew the levels by mission and level; here they are known by world name, which also covers +runworld. cshell/p8_thief.*, one call each from LoadWorld and the two places the weapon model picks its hands. - The levels' handbags, moneybags and money are three new intel types, with popups ScaleFX261-263; the intel folder lists them. An intel item's type is stored as a byte, so the folder compares against 261-263 as bytes. The release build is unchanged (make progress). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With PS2=1 and the PS2 disc image (USA or European: the same files) in rez/isos/ps2/, the modern build gets the PS2 release's three "Nine years ago" levels; without it, nothing changes. - build/ps2/ps2install.py writes everything the levels need into the game directory's custom/, from the disc image (its own ISO9660 reader; the PC files from the game's archives), in about 25 seconds: the three worlds (string IDs remapped, a door sound's typo fixed), their PS2-only textures, the models and skins (the gadgets, young Cate, the police hat, the intel popups), 81 sounds, the gadget icons and the loading photo as PCX. It ends with a check that every file the levels and the attribute recipes name is there. - build/ps2/data/ holds the attribute recipes: MISSIONS (the flashbacks inside missions 3, 5 and 13, as on the PS2; the gadgets one-time), WEAPONS (the Thief Safe Cracker and Thief Lock Pick, appended, and the safe cracker's ammo), INTELITEMS and FX (the new intel), MODELBUTES (the "Thief" style), ATTACHMENTS (the police hats). They need the converted content, so build/ps2/ps2data.py applies them on top of src/modern/data's, not tools/moddata.py. - build/all.sh step 2d writes the levels' text into CRes.dll (ps2strings.py, now reading the ISO too); build/variant.sh installs the rest after the modern data; build/ps2/ps2build.sh does both, and takes out what an earlier install wrote (custom/PS2-DATA.txt lists it). - build/package.sh makes no public archive of a game directory with the PS2 levels: they come from the PS2 disc, which the public archive's install scripts cannot read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The PS2 release's "A Man of Influence" has a secret basement under the Baron's front courtyard that the PC's has not: a kennel off the side yard with a guard dog, a lift down, a shooting gallery with three rounds of targets and a hidden rocket launcher, an indoor "safari" range with a painted sky, a pond and moving targets, a row of cells, a store room, and a second lift that comes up through the courtyard statue. It is optional, with no objective or text of its own, and open only before Cate rings the doorbell. It is in the PS2's first half of the third scene (m07s03_A; the second, m07s03_B, the interview, is the PC's polygon for polygon). With no world compiler or level source to add it to the PC world, the mission plays the PS2's two halves instead of M07S03 (M-P8-09): - the installer converts both (their strings are the PC's: no remap) and the sliding doors' sound, and leaves out two PS2 inventory resets -- the PS2 has no loadout screen, and on the PC they would throw away the player's -- making the basement's crossbow and rocket launcher the mission's one-time weapons instead; - a save made in the PC's M07S03 goes on as the last half, whose end is its end: a world in no mission whose <world>_B is in one is that level (MissionMgr, M-P8-08). The release build is unchanged (make progress). The install check now knows references the retail game is missing too (a dog head skin, a sky texture, eight interview questions with no voice) and does not count them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A PS2 model's piece has a colour it is drawn in and a glow added on top: the safe cracker's wires, buttons and terminals are red, blue, green and orange, and its two LEDs glow red and green. A PC model has neither, so they came out in the skin's plain white and grey. ps2model.bake_colours puts them into the skin: a copy twice as tall, where each coloured piece gets a patch of its own -- the skin under it times its colour, plus its glow -- and its texture coordinates move there. The first-person safe cracker gets that skin (Guns\Skins_PV\PS2SafeCracker_pv_leds.dtx, its PVSkin); the in-hand model, whose pieces are plain, keeps the PS2's. The LEDs are bright, but lit by the room as the rest is: the PC has no glow per piece. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Interface options gain "Main menu Cate": Seasonal (the day's, as before, and the default), Original, Casual, Winter and -- with the PS2 levels -- Young Cate, the PS2 release's young Cate in her catsuit, holding the P38 as the others do (MainMenuCate, M-P8-10). Her menu model is made at install time from the converted in-game one: its mesh, which has the menu model's 25 nodes, on the retail IntHero_Action's one animation, interface4 -- as the menu's casual and winter Cates are the in-game outfits on the menu skeleton -- installed as the IntHero model in the "Thief" style, with her skins under the same name. Her main menu is a fourth main-menu folder (FOLDER_ID_MAIN_THIEF, [FolderMainThief], character CateThief); its layout recipe is the PS2 levels', so without them the choice is not offered and MainMenuCate 4 means seasonal. Backing out of the options to the main menu asks the setting again (the folder history holds the main menu that was showing), so a new choice shows at once. The menu's strings are ours (cres/p8.rc). The release build is unchanged (make progress). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MODERN.md gets package P8 (strings 31700-31799) and its ten items: the conversions (levels, models, sounds, images), the thief safe, the thief levels' look, the new intel, the strings, the game data, saves in a level the PS2 splits, the Baron's training rooms and the main menu's Cate, plus the MainMenuCate setting. BUILDING.md says what make modern PS2=1 does; the changelog lists it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
P9_HaveThiefMenu (her menu model, and the layout section master's recipe now adds) replaces P8_HaveYoungCateMenu, and the PS2 data's own LAYOUT patch goes. The seasonal choice includes the mod's night-time young Cate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The converted worlds' keypads with CanDamage (the PS2's mark) get the property the game reads (M-P9-04). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With the mod installed too, its versions take their place, and a save in the PC world goes on in the last half (M-P9-07). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An intel item's type is a byte: at 261-263 the PS2 build's handbags, moneybags and money were stored as 5-7, and the gallery showed ScaleFX5-7 for them. The retail effects there move to 261-263 (looked up by name). The gallery names them with the mod's strings, else the PS2 build's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…S2 build's Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every world texture the PS2 disc has is installed from it under PS2\ and the converted worlds name those; the PC levels keep the PC's textures of the same names. Before, a texture the PC had was drawn with the PC's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…iles leave Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.