First revision of our scripted... thing

This commit is contained in:
Marco Cawthorne 2023-05-06 13:37:28 -07:00
parent 50d599ef71
commit 1dacf2c46e
Signed by: eukara
GPG key ID: CE2032F0A2882A22
22 changed files with 8702 additions and 4 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
_bin/*
_build/*
_deps/*
_tmp/*

125
README
View file

@ -1,5 +1,122 @@
Half-Life: Shareware Data Half-Life: PAK0.PAK generator
This repository contains scripts to generate a free installation This repository contains scripts to generate a pak0.pak of
of Half-Life. We stripping the content straight from installers Half-Life that is identical to the one that ships on all original disc
of demos and other official, free downloads. pressings, when it still talked to the World Opponent Network
online service.
The Steam releases got rid of .pak files altogether, because they
(at one point) switched to .gcf archives. Since the SteamPipe update,
all files are now completely loose and enforcing file consistency is
impossible for source ports.
These scripts within are stripping the content straight from installers
of demos and other official, free downloads.
This will only build you a pak0.pak file that will pass server purity
checks so that you can play multiplayer via source ports and things.
This will not grant you a complete install of Half-Life. This will
not allow you to play Half-LIfe on Steam or by itself.
We will still have to improvise where other loose files come from.
I've found some good substitutes. If you want it to be truly authentic,
please find a 1.0.0.5 of Game of the Year disc pressing of Half-Life
and rip the data yourself.
Sources:
Half-Life: Uplink (web installer)
Half-Life Patch 1.1.1.0 (English)
Half-Life: Opposing Force - Standalone Demo
Half-Life SDK v2.3 Setup
Steam Installer with Half-Life Cache
Requirements:
- approximately 4 GB of disk space
- working C compiler
- GNU make (probably)
- wget
- magick
Getting started:
Run `./start.sh` and wait a few minutes. Make yourself some tea/coffee.
If you want to speed up the process, get these files off your NFS/NAS:
hl1110.exe
hl_sdk_v23.exe
hluplink.exe
opfordemofull.exe,
steaminstall_halflife.exe
...and place them alongside this README file.
Script explanation:
./build_tools.sh builds bmpfix, {hl,pak}extract, qfiles, rewise and
places them into ./_bin
./dl_sources.sh (no args) downloads and sha512 checks the install
files.
./rip_sources.sh (no args) extracts the files, and does trickery to
make 2 bad-CRC files work
./build_pak0.sh [gamedir] will read games/[gamedir]-pak0.sha256 and
assemble the pak0.pak
./build_loose.sh [gamedir] will read games[gamedir.sha256 and finds
other desired loose files
./ccase.sh fixes case sensitivity issues
the end result is placed into ./_build for you to copy wherever.
All the directories prefixed with '_' can be removed, as they're
created by the scripts.
Thanks:
Xylemon - for being the top dog that kept motivating me and for
delivering pizza onto my desk
Theuaredead` - for lots of research and pointers on where we can
acquire data sets and files
CYBERDEViL - for blessing us with REWise, a sane wise installer
extractor
HeteroChromia420 - for bothering me for years in regards to the
content purity mess
Valve - I know you don't love HL1 anymore, but thanks for bringing
it into this world
License:
Scripts in the root dir are CC0
ccase.sh was distributed by various Linux game ports, unknown author
tools/bmpfix is CC0
tools/gpl-quake/ contains GNU GPL V2 code.
Dependency licenses:
hllib is GNU LGPL 2.1
hlextract is GNU GPL V2
pakextract its own permissive (ISC-styled) license
REWise is GNU GPL V3
Need help:
None of this comes with support, warranty or whatever. Don't bother
ANYONE about this. If you want to improve script compatibility or
whatever, feel free to reach out.

82
build_loose.sh Executable file
View file

@ -0,0 +1,82 @@
#!/bin/sh
# builds a pak0.pak file for a respective gamedir
set -e
usage ()
{
echo Usage: `basename $0` gamedir >&2
exit 2
}
if [ $# -lt 1 ]
then
usage
fi
FILES_OUTDIR="$(pwd)/_build/halflife/$1"
FILES_MISSING="$(pwd)/_build/missing-$1-loose.txt"
find_file ()
{
SEARCHNAME=$(basename "${1}")
#echo "Looking for $SEARCHNAME"
find "./_tmp" -type f -name "${SEARCHNAME}" | while read FOUND
do
CHECK=$(sha256sum "${FOUND}" | cut -d ' ' -f 1)
#echo "$CHECK == $2"
if [ "${CHECK}" = "$2" ]
then
mkdir -p "${FILES_OUTDIR}/$(dirname $1)"
cp -v "${FOUND}" "${FILES_OUTDIR}/$1"
exit 0
fi
done
if [ ! -f "${FILES_OUTDIR}/$1" ]
then
echo "${1}" >> "$FILES_MISSING"
fi
}
find_file_whatever ()
{
echo "Looking for $1"
find "./_tmp" -type f -path "*/${2}/${1}*" | while read FOUND
do
mkdir -p "${FILES_OUTDIR}/$(dirname $1)"
cp -v "${FOUND}" "${FILES_OUTDIR}/$1"
exit 0
done
}
if [ ! -d "$FILES_OUTDIR" ]
then
echo "Please generate a pak0.pak first."
exit 2
fi
if [ -f "$FILES_MISSING" ]
then
rm -v "$FILES_MISSING"
fi
while read LINE
do
FILE=$(echo ${LINE} | cut -d ' ' -f 2)
SUM=$(echo ${LINE} | cut -d ' ' -f 1)
find_file ${FILE} $SUM $1
done < "games/$1.sha256"
# since we don't need to pass purity checks for these
# we'll find the next best equivalent
while read LINE
do
FILE=$(echo ${LINE} | cut -d ' ' -f 2)
find_file_whatever ${FILE} $1
done < "$FILES_MISSING"

89
build_pak0.sh Executable file
View file

@ -0,0 +1,89 @@
#!/bin/sh
# builds a pak0.pak file for a respective gamedir
export PATH=$(pwd)/_bin:$PATH;
set -e
usage ()
{
echo Usage: `basename $0` gamedir >&2
exit 2
}
if [ $# -lt 1 ]
then
usage
fi
PAK0_OUTDIR="$(pwd)/_build/halflife/$1-pak0"
FINAL_TEST=$(cat "sums/$1_pak0.sha512" | cut -d ' ' -f 1)
find_file ()
{
SEARCHNAME=$(basename "${1}")
#echo "Looking for $SEARCHNAME"
find "./_tmp" -type f -name "${SEARCHNAME}" | while read FOUND
do
CHECK=$(sha256sum "${FOUND}" | cut -d ' ' -f 1)
#echo "$CHECK == $2"
if [ "${CHECK}" = "$2" ]
then
mkdir -p "${PAK0_OUTDIR}/$(dirname $1)"
cp -v "${FOUND}" "${PAK0_OUTDIR}/$1"
exit 0
fi
done
if [ ! -f "${PAK0_OUTDIR}/$1" ]
then
echo "${1}" >> "./_build/missing-$3-pak0.txt"
fi
}
# clean up
if [ -d "$PAK0_OUTDIR" ]
then
rm -rf "$PAK0_OUTDIR"
fi
mkdir -p "$PAK0_OUTDIR"
if [ -f "./_build/missing-$1-pak0.txt" ]
then
rm "./_build/missing-$1-pak0.txt"
fi
while read LINE
do
FILE=$(echo ${LINE} | cut -d ' ' -f 2)
SUM=$(echo ${LINE} | cut -d ' ' -f 1)
find_file ${FILE} $SUM $1
done < "games/$1-pak0.sha256"
# move the qfiles script over
mkdir -p "$PAK0_OUTDIR/src/"
cp -v "games/$1.dat" "$PAK0_OUTDIR/src/files.dat"
cd "$PAK0_OUTDIR/src/"
qfiles -pak 0
FINAL_CHECK=$(sha512sum "$PAK0_OUTDIR/pak0.pak" | cut -d ' ' -f 1)
echo "Desired SHA512: ${FINAL_TEST}"
echo "Generated SHA512: ${FINAL_CHECK}"
if [ "${FINAL_CHECK}" = "${FINAL_TEST}" ]
then
echo "$1's pak0.pak has been built and verified!"
else
echo "$1's pak0.pak FAILED the check. Will not pass purity test."
fi
cd "$PAK0_OUTDIR/../"
mkdir -p "./$1"
mv "$PAK0_OUTDIR/pak0.pak" "./$1/pak0.pak"
rm -rf "$PAK0_OUTDIR"

49
build_tools.sh Executable file
View file

@ -0,0 +1,49 @@
#!/bin/sh
set -e
DEPSDIR="$(pwd)/_deps"
BINDIR="$(pwd)/_bin"
INCTOOLDIR="$(pwd)/tools"
if [ -d "$DEPSDIR" ]
then
rm -rf "$DEPSDIR"
fi
if [ -d "$BINDIR" ]
then
rm -rf "$BINDIR"
fi
mkdir "$DEPSDIR"
mkdir "$BINDIR"
cd "$DEPSDIR"
git clone https://notabug.org/CYBERDEViL/REWise
cd REWise
make
mv -v rewise "$BINDIR/rewise"
cd "$DEPSDIR"
git clone https://github.com/RavuAlHemio/hllib
cd hllib/HLLib
make
cd ../HLExtract
make
mv -v hlextract "$BINDIR/hlextract"
cd "$DEPSDIR"
git clone https://github.com/yquake2/pakextract
cd pakextract
make
mv -v pakextract "$BINDIR/pakextract"
cd "$INCTOOLDIR/bmpfix"
cc -o bmpfix bmpfix.c
mv -v bmpfix "$BINDIR/bmpfix"
cd "$INCTOOLDIR/gpl-quake"
cc -o qfiles cmdlib.c qfiles.c
mv -v qfiles "$BINDIR/qfiles"

38
ccase.sh Executable file
View file

@ -0,0 +1,38 @@
#!/bin/sh
usage ()
{
echo Usage: `basename $0` [-r ] file... >&2
exit 2
}
if [ $# -lt 1 ]
then
usage
fi
if [ "$1" = "-r" ]
then
recursive=1
shift
if [ $# -lt 1 ]
then
usage
fi
else
recursive=0
fi
for i in "$@"
do
new=`echo $i | tr "[:upper:]" "[:lower:]"`
if [ "$new" != "$i" ]
then
echo $i "->" $new >&2
mv "$i" "$new"
fi
if [ $recursive = 1 -a -d "$new" ]
then
$0 -r "$new"/*
fi
done

33
dl_sources.sh Executable file
View file

@ -0,0 +1,33 @@
#!/bin/sh
# fetches all of our download sources (and verifies them)
set -e
fetch_resource()
{
BASENAME=$(basename "$1")
SHA512FILE=$(cat "./sums/$BASENAME.sha512")
if [ ! -f "$BASENAME" ]
then
printf "Grabbing $2..."
wget -nc "$1"
printf "\n"
fi
SHA512SUM=$(sha512sum "$BASENAME")
if [ "$SHA512SUM" = "$SHA512FILE" ]
then
printf "$BASENAME has been verified.\n"
else
printf "$BASENAME has the invalid sha512sum. Error!\n"
exit
fi
}
fetch_resource "http://archive.org/download/Half-lifeUplink/hluplink.exe" "Half-Life: Uplink"
fetch_resource "http://archive.org/download/half-life-patches/English/Update 1.1.1.0 English/hl1110.exe" "Half-Life: Patch 1.1.1.0"
fetch_resource "https://archive.org/download/opfor-demo/opfordemofull.exe" "Half-Life: Opposing Force - Demo"
fetch_resource "https://downloads.ammahls.com/HLSDK/hl_sdk_v23.exe"
fetch_resource "http://archive.org/download/steaminstall_halflife/steaminstall_halflife.exe" "Steam Installer with Half-Life Cache"

3453
games/valve-pak0.sha256 Normal file

File diff suppressed because it is too large Load diff

3454
games/valve.dat Normal file

File diff suppressed because it is too large Load diff

23
games/valve.sha256 Normal file
View file

@ -0,0 +1,23 @@
d63e152db6d950f671356c4da0d8a1966e0d940a2166b61678e3a6d46644cd7c xeno.wad
0f5c3ae49af4e72f4f26752c1fd5dfbea8f88859f1097badf8733fa6093a8f95 liquids.wad
d9d16c2c55f02e5767ce6295720cb7032733d3469f2258f665835ff34da3bac4 settings.scr
17726e8174729011c7ea4e1e37b4ccfe7a9aa4abb82c2aaca87872cbe0c106d0 decals.wad
4f27bc35d508c4b7226ebe6d529b00f2cabd3ee989aafe7ce2f23703e98c214e server.cfg
bff7ad40b9b6ff446d56cf3fd05fd2e50c8d8d186dade45549e3313680815e82 spraypaint.wad
38ababf773463fdf6133005d13e543098fc42392b458057f239469b764691300 halflife.wad
eda968bb31d28c3930509b303c35dd576d7fef98d68c67a3bee9d1846a456b6e woncomm.lst
cd36d358e0a0ab5f654816a0e3d606e1267aa6014ff9f11462b3b4ede5f59487 profile.lst
8aa1d462cf294875fe87f7a8197d05b385941959a82e1e614cd02429f4ef12cf liblist.gam
efce3f5735ffb05ccf493c980bd61b774e43ce37ec12c0402d43400e07a6743e mapcycle.txt
6fd53d6ef8d704299734018e3069ec12551e7fb2065804a1d4e5c936ac4033bd gfx.wad
4bbc4680030a300fc535279ab08362e5b5ded8189065f852b3b78052ddfd11bf media/launch_dnmenu1.wav
4ce170dfa11f980075f8b6a8a85c3cf78eb59f8766a26b721bff0910ad3baf2d media/valve.avi
f3429e06124e28f6a69e6ef6bcb89d22103612158de6a0f8348725be1e9ea4b3 media/sierra.avi
bb580215824dd89825f114f4fbe5514f0e9783a1ca7bb7aed2376fadc349b6aa media/launch_select2.wav
5140ee43c6ba8cfab956c405f22f4ec989f427305d5b921be115b2c789451b3f media/launch_glow1.wav
894ef53ebfaad82a3b2c900b4d2eff5ba4e8fdf1ee339cdbb2e82f6e614fb1df media/launch_select1.wav
89eea4b29e3c5272a688e1a42db8a17f6b878c805ffea467edb1e5ad03b47f3d media/logo.avi
3a8178df0cda00bf44bf7982ac5f260ba4335bc661da83a06ee99faa379f530b media/launch_deny1.wav
913ead8450ba2e23c2b10aad5bf29ba923f21fb1ba58943044081a7938ddf915 media/launch_upmenu1.wav
98e2d0a6c5a8c0adf9f75bdbe627b433d36d2d9c26a7b7843fe8ea892b6d7356 media/launch_deny2.wav
b9ac3a6c455fa54a11d4f00f8248909800b8b19f84e84bb35e826e4c137f262d cached.wad

49
rip_sources.sh Executable file
View file

@ -0,0 +1,49 @@
#!/bin/sh
# extracts all the sources into ./_tmp that we got
# with dl_sources.sh
export PATH=$(pwd)/_bin:$PATH;
set -e
x_rewise()
{
mkdir "./_tmp/$1"
rewise -x "./_tmp/$1" "$1"
}
sz_extract()
{
7z x "$1"
}
# clean up
if [ -d "./_tmp" ]
then
rm -rf "./_tmp"
fi
mkdir "./_tmp"
# extract our sources
x_rewise "hluplink.exe"
x_rewise "hl1110.exe"
x_rewise "opfordemofull.exe"
x_rewise "hl_sdk_v23.exe"
x_rewise "steaminstall_halflife.exe"
mkdir -p "./_tmp/hluplink-pak0"
pakextract -o "./_tmp/hluplink-pak0" "./_tmp/hluplink.exe/MAINDIR/valve/pak0.PAK"
mkdir -p "./_tmp/opfordemofull-pak0"
pakextract -o "./_tmp/opfordemofull-pak0" "./_tmp/opfordemofull.exe/MAINDIR/valve/pak0.PAK"
mkdir -p "./_tmp/half-life.gcf"
hlextract -p "./_tmp/steaminstall_halflife.exe/MAINDIR/SteamApps/half-life.gcf" -d "./_tmp/half-life.gcf" -e "root/valve/"
./ccase.sh -r "./_tmp"
# if anything goes wrong here, it's probably imagemagick messing with the image
magick "./_tmp/hluplink-pak0/gfx/shell/btns_main.bmp" -compress none -crop 156x4836+0+0 BMP3:"./_tmp/btns_main.bmp"
bmpfix "./_tmp/hl1110.exe/maindir/valve/models/player/hgrunt/hgrunt.bmp"

14
start.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/sh
set -e
./build_tools.sh
./dl_sources.sh
./rip_sources.sh
./build_pak0.sh valve
./build_loose.sh valve
# the edge cases we simply couldn't automatically fetch, due to path/name quirks
cp -v "./_tmp/hl1110.exe/maindir/valve/settings.scr" "./_build/halflife/valve/settings.scr"
cp -v "./_tmp/hl1110.exe/maindir/valve/woncomm.lst" "./_build/halflife/valve/woncomm.lst"
cp -v "./_tmp/opfordemofull.exe/maindir/valve/media/sierra.avi" "./_build/halflife/valve/media/sierra.avi"
cp -v "./_tmp/hluplink.exe/maindir/media/intro.avi" "./_build/halflife/valve/media/valve.avi"
cp -v "./_tmp/hluplink.exe/maindir/media/uplink.avi" "./_build/halflife/valve/media/logo.avi"

1
sums/hl1110.exe.sha512 Normal file
View file

@ -0,0 +1 @@
b6f7e2142a45b6e56acc9a0b3fe478736b04f7a845cee9977e06b591a137a66cadcaa706e2ba47919cd30e733baf8f32e4dcc2cd608c00b4a0da865562cbdbe8 hl1110.exe

View file

@ -0,0 +1 @@
c3857ac8c5ff657e0a0d36661d251e250d9ff9e23c728d5079c194cedb3c92a38ab34577f0cf4c684852e99c51dfec58654ff41e8d1795efba3fa6a5daf7e82f hl_sdk_v23.exe

1
sums/hluplink.exe.sha512 Normal file
View file

@ -0,0 +1 @@
2629fd06db71f2ea8bd7937ee271c7dd8804c0b570b6ccd0d82a93edd94a11cd0b9736719a9a9e4c1545bc11abaef52c05155188970b762d0afbe4ff0a8aa753 hluplink.exe

View file

@ -0,0 +1 @@
a0b30a419b23d9a4a9750ee89a4827be60e501b8ab2e74292040f8a6c27ab25e879bc2496cdebb2fb957b2e86dc4d5bfc29b01c94b6005d5940343b3c6607ee7 opfordemofull.exe

View file

@ -0,0 +1 @@
865027728d38d92ae6c6a05f9c72da162372ab91b40911c716dc62d4c024fe46b21192429d3a25ca68a9d32d034575ef1c5f7a534abe7e8977eeff8db9dd7b04 steaminstall_halflife.exe

1
sums/valve_pak0.sha512 Normal file
View file

@ -0,0 +1 @@
d548f6a62174e30b651a63ef5725c9474409ab4b8c4e5246d179b4816acf7e554f92a36b9c46e456633781e94b3c52c8f31c7887d771c11b6c840be35ddd6868 /usr/share/games/halflife/valve/pak0.pak

144
tools/bmpfix/bmpfix.c Normal file
View file

@ -0,0 +1,144 @@
/* this program is dedicated to all the cyberpunks out there */
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
typedef unsigned char byte;
/* the format is too annoying for me to give a damn */
static byte bmp_header[54];
static byte bmp_palette[1024];
static byte bmp_buffer[32800];
typedef union {
int rgba:32;
struct {
byte b:8;
byte g:8;
byte r:8;
byte a:8;
} u;
} pixel_t;
pixel_t bmp_pal[256] = {
0xffffff, 0xdfffbb, 0xcbefa3, 0xb7df8b, 0xa7cf77, 0x97bf63, 0x87b353,
0x77a343, 0x679333, 0x5b8327, 0x4f771b, 0x3f6713, 0x33570b, 0x2b4707,
0x1f3700, 0x172b00, 0xfff77f, 0xefeb77, 0xe3df6f, 0xd7cf67, 0xc7c35f,
0xbbb75b, 0xafab53, 0x9f9f4b, 0x939347, 0x87833f, 0x7b7737, 0x6b6b33,
0x5f5f2b, 0x534f23, 0x43431f, 0x373717, 0x2b2b13, 0x27270f, 0x27270f,
0x23230f, 0x23230f, 0x1f230f, 0x1b1f0b, 0x1b1f0b, 0x1b1b0b, 0x171b0b,
0x171b0b, 0x131707, 0x131707, 0x0f1307, 0x0f1307, 0x0f1307, 0x9baf87,
0x8f9f77, 0x83936b, 0x77875f, 0x6f7753, 0x636b47, 0x575f3b, 0x4f5333,
0x434b2b, 0x3b4727, 0x334323, 0x2b3f1f, 0x233717, 0x1b3313, 0x132f13,
0x0f2b0f, 0xefcfaf, 0xe7c7a7, 0xdfbf9f, 0xdbb79b, 0xd3b393, 0xcfab8b,
0xc7a387, 0xbf9b7f, 0xbb977b, 0xbf9373, 0xc38f6b, 0xc78b63, 0xcb875b,
0xcf8353, 0xd37f4b, 0xdb7b43, 0xd36f3f, 0xcb673b, 0xc35f37, 0xbb5733,
0xb3532f, 0xab4b2b, 0xa3432b, 0x9f3b27, 0x973723, 0x8f2f1f, 0x872b1f,
0x7f231b, 0x771f17, 0x6f1b17, 0x671713, 0x631313, 0xb7876f, 0xab7b63,
0xa36f57, 0x9b634b, 0x93573f, 0x874f37, 0x7f472f, 0x773b23, 0x6b331f,
0x632b17, 0x5b230f, 0x531f0b, 0x471707, 0x3f1300, 0x370f00, 0x2f0b00,
0xd3d7bb, 0xc7cbaf, 0xbbbfa3, 0xafb397, 0xa3a78f, 0x979b83, 0x8f8f77,
0x83836f, 0x777763, 0x6b6b57, 0x5f5f4f, 0x535343, 0x47473b, 0x3b3b2f,
0x333327, 0x27271f, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff,
0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff,
0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff,
0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff,
0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0x70527a,
0x6a4d73, 0x62486b, 0x5c4263, 0x503a57, 0x49354f, 0x423047, 0x3b2a40,
0x332538, 0x2a1e2e, 0x231926, 0x1a121c, 0x150f17, 0x0b080c, 0x070507,
0x000000, 0x70527a, 0x6a4d73, 0x62486b, 0x5b4263, 0x4f3a57, 0x4a354f,
0x423047, 0x3a2a40, 0x342538, 0x2a1e2e, 0x231926, 0x1b071f, 0x130717,
0x0b000f, 0x070007, 0x000000, 0x52737a, 0x4d6773, 0x48646b, 0x415a61,
0x3c5359, 0x354a4f, 0x2e4045, 0x29393d, 0x223033, 0x1e2b2e, 0x182123,
0x141c1e, 0x0f1517, 0x0a0e0f, 0x050707, 0x000000, 0x52727a, 0x4d6a73,
0x48636b, 0x425d63, 0x3a5257, 0x354a4f, 0x304247, 0x2a3c40, 0x253438,
0x1e2b2e, 0x192326, 0x141d1e, 0x0f1517, 0x0a0e0f, 0x050707, 0x000000,
0xffffff, 0xf7f7f7, 0xefefef, 0xe7e7e7, 0xdfdfdf, 0xd7d7d7, 0xcfcfcf,
0xc7c7c7, 0xbfbfbf, 0xb7b7b7, 0xafafaf, 0xa7a7a7, 0x9f9f9f, 0x979797,
0x8f8f8f, 0x878787, 0x7f7f7f, 0x777777, 0x6f6f6f, 0x676767, 0x5f5f5f,
0x575757, 0x4f4f4f, 0x474747, 0x3f3f3f, 0x373737, 0x2f2f2f, 0x272727,
0x1f1f1f, 0x171717, 0x0f0f0f, 0x040404
};
byte
find_in_pal(byte r, byte g, byte b)
{
for (int i = 0; i < 256; i++) {
if (bmp_pal[i].u.r == r && bmp_pal[i].u.g == g && bmp_pal[i].u.b == b)
return (byte)i;
}
return 0;
}
void
process_bmp(char *filename)
{
FILE *fp;
struct stat bmp_st;
if ((fp = fopen(filename, "rb")) == NULL) {
exit(0);
}
/* There are no other types of palette lumps. Sorry */
stat(filename, &bmp_st);
if (bmp_st.st_size != 33878) {
fprintf(stderr, "%s has invalid player bitmap size, skipping\n", filename);
return;
}
/* lazily read the clown format in */
fread(bmp_header, 1, 54, fp);
fread(bmp_palette, 1, 1024, fp);
fread(bmp_buffer, 1, 32800, fp);
fclose(fp);
/* convert from 8-bit to 24-bit */
for (int i = 0; i < 32800; i += 1) {
int palId = bmp_buffer[i] * 4;
/* get 24-bit values */
byte r = bmp_palette[palId + 2];
byte g = bmp_palette[palId + 1];
byte b = bmp_palette[palId + 0];
/* assign the index from the good palette */
bmp_buffer[i] = find_in_pal(r, g, b);
}
/* shove the old palette into the new place */
for (int i = 0; i < 256; i += 1) {
int id = i * 4;
bmp_palette[id+2] = bmp_pal[i].u.r;
bmp_palette[id+1] = bmp_pal[i].u.g;
bmp_palette[id+0] = bmp_pal[i].u.b;
}
if ((fp = fopen(filename, "wb")) == NULL) {
exit(0);
}
fwrite(bmp_header, 1, 54, fp);
fwrite(bmp_palette, 1, 1024, fp);
fwrite(bmp_buffer, 1, 32800, fp);
fclose(fp);
}
int
main(int argc, char *argv[])
{
int c;
short p;
FILE *fPAL;
if (argc <= 1) {
fprintf(stderr, "usage: bmpfix [file ...]\n");
return 1;
}
for (c = 1; c < argc; c++)
process_bmp(argv[c]);
return 0;
}

867
tools/gpl-quake/cmdlib.c Normal file
View file

@ -0,0 +1,867 @@
// cmdlib.c
#include "cmdlib.h"
#include <sys/types.h>
#include <sys/stat.h>
#ifdef WIN32
#include <direct.h>
#endif
#ifdef NeXT
#include <libc.h>
#endif
#define PATHSEPERATOR '/'
// set these before calling CheckParm
int myargc;
char **myargv;
char com_token[1024];
qboolean com_eof;
qboolean archive;
char archivedir[1024];
/*
=================
Error
For abnormal program terminations
=================
*/
void Error (char *error, ...)
{
va_list argptr;
printf ("************ ERROR ************\n");
va_start (argptr,error);
vprintf (error,argptr);
va_end (argptr);
printf ("\n");
exit (1);
}
/*
qdir will hold the path up to the quake directory, including the slash
f:\quake\
/raid/quake/
gamedir will hold qdir + the game directory (id1, id2, etc)
*/
char qdir[1024];
char gamedir[1024];
void SetQdirFromPath (char *path)
{
char temp[1024];
char *c;
if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':'))
{ // path is partial
Q_getwd (temp);
strcat (temp, path);
path = temp;
}
// search for "quake" in path
for (c=path ; *c ; c++)
if (!Q_strncasecmp (c, "halflife", 8))
{
strncpy (qdir, path, c+9-path);
printf ("qdir: %s\n", qdir);
c += 9;
while (*c)
{
if (*c == '/' || *c == '\\')
{
strncpy (gamedir, path, c+1-path);
printf ("gamedir: %s\n", gamedir);
return;
}
c++;
}
Error ("No gamedir in %s", path);
return;
}
Error ("SeetQdirFromPath: no 'halflife' in %s", path);
}
char *ExpandPath (char *path)
{
static char full[1024];
if (!qdir)
Error ("ExpandPath called without qdir set");
if (path[0] == '/' || path[0] == '\\' || path[1] == ':')
return path;
sprintf (full, "%s%s", qdir, path);
return full;
}
char *ExpandPathAndArchive (char *path)
{
char *expanded;
char archivename[1024];
expanded = ExpandPath (path);
if (archive)
{
sprintf (archivename, "%s/%s", archivedir, path);
CopyFile (expanded, archivename);
}
return expanded;
}
char *copystring(char *s)
{
char *b;
b = malloc(strlen(s)+1);
strcpy (b, s);
return b;
}
/*
================
I_FloatTime
================
*/
double I_FloatTime (void)
{
time_t t;
time (&t);
return t;
#if 0
// more precise, less portable
struct timeval tp;
struct timezone tzp;
static int secbase;
gettimeofday(&tp, &tzp);
if (!secbase)
{
secbase = tp.tv_sec;
return tp.tv_usec/1000000.0;
}
return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
#endif
}
void Q_getwd (char *out)
{
#ifdef WIN32
_getcwd (out, 256);
strcat (out, "\\");
#else
getwd (out);
#endif
}
void Q_mkdir (char *path)
{
#ifdef WIN32
if (_mkdir (path) != -1)
return;
#else
if (mkdir (path, 0777) != -1)
return;
#endif
if (errno != EEXIST)
Error ("mkdir %s: %s",path, strerror(errno));
}
/*
============
FileTime
returns -1 if not present
============
*/
int FileTime (char *path)
{
struct stat buf;
if (stat (path,&buf) == -1)
return -1;
return buf.st_mtime;
}
/*
==============
COM_Parse
Parse a token out of a string
==============
*/
char *COM_Parse (char *data)
{
int c;
int len;
len = 0;
com_token[0] = 0;
if (!data)
return NULL;
// skip whitespace
skipwhite:
while ( (c = *data) <= ' ')
{
if (c == 0)
{
com_eof = true;
return NULL; // end of file;
}
data++;
}
// skip // comments
if (c=='/' && data[1] == '/')
{
while (*data && *data != '\n')
data++;
goto skipwhite;
}
// handle quoted strings specially
if (c == '\"')
{
data++;
do
{
c = *data++;
if (c=='\"')
{
com_token[len] = 0;
return data;
}
com_token[len] = c;
len++;
} while (1);
}
// parse single characters
if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
{
com_token[len] = c;
len++;
com_token[len] = 0;
return data+1;
}
// parse a regular word
do
{
com_token[len] = c;
data++;
len++;
c = *data;
if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
break;
} while (c>32);
com_token[len] = 0;
return data;
}
int Q_strncasecmp (char *s1, char *s2, int n)
{
int c1, c2;
while (1)
{
c1 = *s1++;
c2 = *s2++;
if (!n--)
return 0; // strings are equal until end point
if (c1 != c2)
{
if (c1 >= 'a' && c1 <= 'z')
c1 -= ('a' - 'A');
if (c2 >= 'a' && c2 <= 'z')
c2 -= ('a' - 'A');
if (c1 != c2)
return -1; // strings not equal
}
if (!c1)
return 0; // strings are equal
}
return -1;
}
int Q_strcasecmp (char *s1, char *s2)
{
return Q_strncasecmp (s1, s2, 99999);
}
char *strupr (char *start)
{
char *in;
in = start;
while (*in)
{
*in = toupper(*in);
in++;
}
return start;
}
char *strlower (char *start)
{
char *in;
in = start;
while (*in)
{
*in = tolower(*in);
in++;
}
return start;
}
/*
=============================================================================
MISC FUNCTIONS
=============================================================================
*/
/*
=================
CheckParm
Checks for the given parameter in the program's command line arguments
Returns the argument number (1 to argc-1) or 0 if not present
=================
*/
int CheckParm (char *check)
{
int i;
for (i = 1;i<myargc;i++)
{
if ( !Q_strcasecmp(check, myargv[i]) )
return i;
}
return 0;
}
/*
================
filelength
================
*/
int filelength (FILE *f)
{
int pos;
int end;
pos = ftell (f);
fseek (f, 0, SEEK_END);
end = ftell (f);
fseek (f, pos, SEEK_SET);
return end;
}
FILE *SafeOpenWrite (char *filename)
{
FILE *f;
f = fopen(filename, "wb");
if (!f)
Error ("Error opening %s: %s",filename,strerror(errno));
return f;
}
FILE *SafeOpenRead (char *filename)
{
FILE *f;
f = fopen(filename, "rb");
if (!f)
Error ("Error opening %s: %s",filename,strerror(errno));
return f;
}
void SafeRead (FILE *f, void *buffer, int count)
{
if ( fread (buffer, 1, count, f) != (size_t)count)
Error ("File read failure");
}
void SafeWrite (FILE *f, void *buffer, int count)
{
if (fwrite (buffer, 1, count, f) != (size_t)count)
Error ("File read failure");
}
/*
==============
LoadFile
==============
*/
int LoadFile (char *filename, void **bufferptr)
{
FILE *f;
int length;
void *buffer;
f = SafeOpenRead (filename);
length = filelength (f);
buffer = malloc (length+1);
((char *)buffer)[length] = 0;
SafeRead (f, buffer, length);
fclose (f);
*bufferptr = buffer;
return length;
}
/*
==============
SaveFile
==============
*/
void SaveFile (char *filename, void *buffer, int count)
{
FILE *f;
f = SafeOpenWrite (filename);
SafeWrite (f, buffer, count);
fclose (f);
}
void DefaultExtension (char *path, char *extension)
{
char *src;
//
// if path doesn't have a .EXT, append extension
// (extension should include the .)
//
src = path + strlen(path) - 1;
while (*src != PATHSEPERATOR && src != path)
{
if (*src == '.')
return; // it has an extension
src--;
}
strcat (path, extension);
}
void DefaultPath (char *path, char *basepath)
{
char temp[128];
if (path[0] == PATHSEPERATOR)
return; // absolute path location
strcpy (temp,path);
strcpy (path,basepath);
strcat (path,temp);
}
void StripFilename (char *path)
{
int length;
length = strlen(path)-1;
while (length > 0 && path[length] != PATHSEPERATOR)
length--;
path[length] = 0;
}
void StripExtension (char *path)
{
int length;
length = strlen(path)-1;
while (length > 0 && path[length] != '.')
{
length--;
if (path[length] == '/')
return; // no extension
}
if (length)
path[length] = 0;
}
/*
====================
Extract file parts
====================
*/
void ExtractFilePath (char *path, char *dest)
{
char *src;
src = path + strlen(path) - 1;
//
// back up until a \ or the start
//
while (src != path && *(src-1) != PATHSEPERATOR)
src--;
memcpy (dest, path, src-path);
dest[src-path] = 0;
}
void ExtractFileBase (char *path, char *dest)
{
char *src;
src = path + strlen(path) - 1;
//
// back up until a \ or the start
//
while (src != path && *(src-1) != PATHSEPERATOR)
src--;
while (*src && *src != '.')
{
*dest++ = *src++;
}
*dest = 0;
}
void ExtractFileExtension (char *path, char *dest)
{
char *src;
src = path + strlen(path) - 1;
//
// back up until a . or the start
//
while (src != path && *(src-1) != '.')
src--;
if (src == path)
{
*dest = 0; // no extension
return;
}
strcpy (dest,src);
}
/*
==============
ParseNum / ParseHex
==============
*/
int ParseHex (char *hex)
{
char *str;
int num;
num = 0;
str = hex;
while (*str)
{
num <<= 4;
if (*str >= '0' && *str <= '9')
num += *str-'0';
else if (*str >= 'a' && *str <= 'f')
num += 10 + *str-'a';
else if (*str >= 'A' && *str <= 'F')
num += 10 + *str-'A';
else
Error ("Bad hex number: %s",hex);
str++;
}
return num;
}
int ParseNum (char *str)
{
if (str[0] == '$')
return ParseHex (str+1);
if (str[0] == '0' && str[1] == 'x')
return ParseHex (str+2);
return atol (str);
}
/*
============================================================================
BYTE ORDER FUNCTIONS
============================================================================
*/
#ifdef _SGI_SOURCE
#define __BIG_ENDIAN__
#endif
#ifdef __BIG_ENDIAN__
short LittleShort (short l)
{
byte b1,b2;
b1 = l&255;
b2 = (l>>8)&255;
return (b1<<8) + b2;
}
short BigShort (short l)
{
return l;
}
int LittleLong (int l)
{
byte b1,b2,b3,b4;
b1 = l&255;
b2 = (l>>8)&255;
b3 = (l>>16)&255;
b4 = (l>>24)&255;
return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
}
int BigLong (int l)
{
return l;
}
float LittleFloat (float l)
{
union {byte b[4]; float f;} in, out;
in.f = l;
out.b[0] = in.b[3];
out.b[1] = in.b[2];
out.b[2] = in.b[1];
out.b[3] = in.b[0];
return out.f;
}
float BigFloat (float l)
{
return l;
}
#else
short BigShort (short l)
{
byte b1,b2;
b1 = l&255;
b2 = (l>>8)&255;
return (b1<<8) + b2;
}
short LittleShort (short l)
{
return l;
}
int BigLong (int l)
{
byte b1,b2,b3,b4;
b1 = l&255;
b2 = (l>>8)&255;
b3 = (l>>16)&255;
b4 = (l>>24)&255;
return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
}
int LittleLong (int l)
{
return l;
}
float BigFloat (float l)
{
union {byte b[4]; float f;} in, out;
in.f = l;
out.b[0] = in.b[3];
out.b[1] = in.b[2];
out.b[2] = in.b[1];
out.b[3] = in.b[0];
return out.f;
}
float LittleFloat (float l)
{
return l;
}
#endif
//=======================================================
// FIXME: byte swap?
// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
// and the initial and final xor values shown below... in other words, the
// CCITT standard CRC used by XMODEM
#define CRC_INIT_VALUE 0xffff
#define CRC_XOR_VALUE 0x0000
static unsigned short crctable[256] =
{
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};
void CRC_Init(unsigned short *crcvalue)
{
*crcvalue = CRC_INIT_VALUE;
}
void CRC_ProcessByte(unsigned short *crcvalue, byte data)
{
*crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
}
unsigned short CRC_Value(unsigned short crcvalue)
{
return crcvalue ^ CRC_XOR_VALUE;
}
//=============================================================================
/*
============
CreatePath
============
*/
void CreatePath (char *path)
{
char *ofs, c;
for (ofs = path+1 ; *ofs ; ofs++)
{
c = *ofs;
if (c == '/' || c == '\\')
{ // create the directory
*ofs = 0;
Q_mkdir (path);
*ofs = c;
}
}
}
/*
============
CopyFile
Used to archive source files
============
*/
void CopyFile (char *from, char *to)
{
void *buffer;
int length;
length = LoadFile (from, &buffer);
CreatePath (to);
SaveFile (to, buffer, length);
free (buffer);
}

97
tools/gpl-quake/cmdlib.h Normal file
View file

@ -0,0 +1,97 @@
// cmdlib.h
#ifndef __CMDLIB__
#define __CMDLIB__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <time.h>
#include <stdarg.h>
#ifndef __BYTEBOOL__
#define __BYTEBOOL__
typedef enum {false, true} qboolean;
typedef unsigned char byte;
#endif
// the dec offsetof macro doesn't work very well...
#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier)
// set these before calling CheckParm
extern int myargc;
extern char **myargv;
char *strupr (char *in);
char *strlower (char *in);
int Q_strncasecmp (char *s1, char *s2, int n);
int Q_strcasecmp (char *s1, char *s2);
void Q_getwd (char *out);
int filelength (FILE *f);
int FileTime (char *path);
void Q_mkdir (char *path);
extern char qdir[1024];
extern char gamedir[1024];
void SetQdirFromPath (char *path);
char *ExpandPath (char *path);
char *ExpandPathAndArchive (char *path);
double I_FloatTime (void);
void Error (char *error, ...);
int CheckParm (char *check);
FILE *SafeOpenWrite (char *filename);
FILE *SafeOpenRead (char *filename);
void SafeRead (FILE *f, void *buffer, int count);
void SafeWrite (FILE *f, void *buffer, int count);
int LoadFile (char *filename, void **bufferptr);
void SaveFile (char *filename, void *buffer, int count);
void DefaultExtension (char *path, char *extension);
void DefaultPath (char *path, char *basepath);
void StripFilename (char *path);
void StripExtension (char *path);
void ExtractFilePath (char *path, char *dest);
void ExtractFileBase (char *path, char *dest);
void ExtractFileExtension (char *path, char *dest);
int ParseNum (char *str);
short BigShort (short l);
short LittleShort (short l);
int BigLong (int l);
int LittleLong (int l);
float BigFloat (float l);
float LittleFloat (float l);
char *COM_Parse (char *data);
extern char com_token[1024];
extern qboolean com_eof;
char *copystring(char *s);
void CRC_Init(unsigned short *crcvalue);
void CRC_ProcessByte(unsigned short *crcvalue, byte data);
unsigned short CRC_Value(unsigned short crcvalue);
void CreatePath (char *path);
void CopyFile (char *from, char *to);
extern qboolean archive;
extern char archivedir[1024];
#endif

179
tools/gpl-quake/qfiles.c Normal file
View file

@ -0,0 +1,179 @@
#include "cmdlib.h"
#define MAX_FILES 4096
#define MAX_DATA_PATH 512
char precache_files[MAX_FILES][MAX_DATA_PATH];
int precache_files_block[MAX_FILES];
int numfiles;
typedef struct
{
char name[56];
int filepos, filelen;
} packfile_t;
typedef struct
{
char id[4];
int dirofs;
int dirlen;
} packheader_t;
packfile_t pfiles[4096], *pf;
FILE *packhandle;
int packbytes;
/*
===========
PackFile
Copy a file into the pak file
===========
*/
void PackFile (char *src, char *name)
{
FILE *in;
int remaining, count;
char buf[4096];
if ( (byte *)pf - (byte *)pfiles > sizeof(pfiles) )
Error ("Too many files in pak file");
in = SafeOpenRead (src);
remaining = filelength (in);
pf->filepos = LittleLong (ftell (packhandle));
pf->filelen = LittleLong (remaining);
strcpy (pf->name, name);
printf ("%64s : %7i\n", pf->name, remaining);
packbytes += remaining;
while (remaining)
{
if (remaining < sizeof(buf))
count = remaining;
else
count = sizeof(buf);
SafeRead (in, buf, count);
SafeWrite (packhandle, buf, count);
remaining -= count;
}
fclose (in);
pf++;
}
/*
===========
CopyQFiles
===========
*/
void CopyQFiles (int blocknum)
{
int i, p;
char srcfile[1024];
char destfile[1024];
char name[1024];
packheader_t header;
int dirlen;
unsigned short crc;
// create a pak file
pf = pfiles;
sprintf (destfile, "%spak%i.pak", gamedir, blocknum);
packhandle = SafeOpenWrite (destfile);
SafeWrite (packhandle, &header, sizeof(header));
blocknum++;
for (i=0 ; i<numfiles ; i++)
{
if (precache_files_block[i] != blocknum)
continue;
sprintf (srcfile,"%s%s",gamedir, precache_files[i]);
PackFile (srcfile, precache_files[i]);
}
header.id[0] = 'P';
header.id[1] = 'A';
header.id[2] = 'C';
header.id[3] = 'K';
dirlen = (byte *)pf - (byte *)pfiles;
header.dirofs = LittleLong(ftell (packhandle));
header.dirlen = LittleLong(dirlen);
SafeWrite (packhandle, pfiles, dirlen);
fseek (packhandle, 0, SEEK_SET);
SafeWrite (packhandle, &header, sizeof(header));
fclose (packhandle);
// do a crc of the file
CRC_Init (&crc);
for (i=0 ; i<dirlen ; i++)
CRC_ProcessByte (&crc, ((byte *)pfiles)[i]);
i = pf - pfiles;
printf ("%i files packed in %i bytes (%i crc)\n",i, packbytes, crc);
}
/*
=============
ReadFiles
=============
*/
int ReadFiles (void)
{
FILE *f;
int i;
f = SafeOpenRead ("files.dat");
fscanf(f, "%i\n", &numfiles);
for (i = 0; i < numfiles ; i++) {
fscanf (f, "%i %s\n", &precache_files_block[i], precache_files[i]);
printf("%s\n", precache_files[i]);
}
fclose (f);
printf ("%i files\n", numfiles);
}
/*
=============
main
=============
*/
int main (int argc, char **argv)
{
if (argc == 1)
{
printf ("qfiles -pak <0 / 1> : build a .pak file\n");
exit (1);
}
SetQdirFromPath ("");
ReadFiles ();
if (!strcmp (argv[1], "-pak"))
{
CopyQFiles (atoi(argv[2]));
}
else
Error ("unknown command: %s", argv[1]);
return 0;
}