Update cwolfmap

This commit is contained in:
Cong
2024-03-16 14:19:21 +11:00
parent 8e219065fc
commit 8a97e0c557
37 changed files with 15910 additions and 113 deletions

View File

@@ -2,7 +2,7 @@
"Version": 16,
"Title": "Spear of Destiny Mission 2: Return to Danger",
"Author": "FormGen Corporation",
"Description": "Six weeks after the Spear of Destiny has been brought out of enemy hands, the Axis mounts a successful commando raid to recover it! After a bloody battle and narrow escape, it's taken to the Nazis' Secret Scandinavian Base, excavated from the solid rock of a fjord. The fortress is said to be impregnable!",
"Description": "",
"Ammo": true,
"WeaponPersist": true,
"SkipWeaponMenu": true,

View File

@@ -2,7 +2,7 @@
"Version": 16,
"Title": "Spear of Destiny Mission 2: Return to Danger",
"Author": "FormGen Corporation",
"Description": "Six weeks after the Spear of Destiny has been brought out of enemy hands, the Axis mounts a successful commando raid to recover it! After a bloody battle and narrow escape, it's taken to the Nazis' Secret Scandinavian Base, excavated from the solid rock of a fjord. The fortress is said to be impregnable!",
"Description": "",
"Ammo": true,
"SkipWeaponMenu": true,
"RandomPickups": false,

View File

@@ -2,7 +2,7 @@
"Version": 16,
"Title": "Spear of Destiny Mission 3: Ultimate Challenge",
"Author": "FormGen Corporation",
"Description": "As the Allies' top agent, you face your toughest challenge yet! Learning from his past mistakes, Hitler has expanded his subterranean command bunker beneath the chancellery in Berlin so that he can keep the Spear of Destiny nearby and well-guarded!\n\nCalling upon the dark forces of the occult, Hitler can see into the future and obtain the plans to future weapon systems!",
"Description": "",
"Ammo": true,
"WeaponPersist": true,
"SkipWeaponMenu": true,

View File

@@ -2,7 +2,7 @@
"Version": 16,
"Title": "Spear of Destiny Mission 2: Return to Danger",
"Author": "FormGen Corporation",
"Description": "Six weeks after the Spear of Destiny has been brought out of enemy hands, the Axis mounts a successful commando raid to recover it! After a bloody battle and narrow escape, it's taken to the Nazis' Secret Scandinavian Base, excavated from the solid rock of a fjord. The fortress is said to be impregnable!",
"Description": "",
"Ammo": true,
"SkipWeaponMenu": true,
"RandomPickups": false,

View File

@@ -2,7 +2,7 @@
"Version": 16,
"Title": "Spear of Destiny",
"Author": "id Software",
"Description": "It's World War II and you are B.J. Blazkowicz, the Allies' most valuable agent. In the midst of the German Blitzkrieg, the Spear that pierced the side of Christ is taken from Versailles by the Nazis and secured in the impregnable Castle Wolfenstein. According to legend, no man can be defeated when he has the Spear. Hitler believes himself to be invincible with the power of the Spear as his brutal army sweeps across Europe.\n\nYour mission is to infiltrate the heavily guarded Nazi stronghold and recapture the Spear from an already unbalanced Hitler. The loss of his most coveted weapon could push him over the edge. It could also get you ripped to pieces.",
"Description": "",
"Ammo": true,
"WeaponPersist": true,
"SkipWeaponMenu": true,

View File

@@ -2,7 +2,7 @@
"Version": 16,
"Title": "Wolfenstein 2D (episode 1)",
"Author": "id Software",
"Description": "Captured in your attempt to grab the secret plans, you were taken to the Nazi prison Castle Wolfenstein for questioning and eventual execution. Now for twelve long days you've been imprisoned beneath the castle fortress. Just beyond your cell door sits a lone thick-necked Nazi guard. He assisted an SS Dentist / Mechanic in an attempt to jump start your tonsils earlier that morning. You're at your breaking point! Quivering on the floor you beg for medical assistance in return for information. His face hints a smug grin of victory as he reaches for his keys. He opens the door, tumblers in the lock echo through the corridors and the door squeaks open. HIS MISTAKE!\n\nA single kick to his knee sends him to the floor. Giving him your version of the victory sign, you grab his knife and quickly finish the job. You stand over the guard's fallen body, grabbing frantically for his gun. You're not sure if the other guards heard his muffled scream. Deep in the belly of a Nazi dungeon, you must escape. This desperate act has sealed your fate-get out or die trying.",
"Description": "",
"Ammo": true,
"WeaponPersist": true,
"SkipWeaponMenu": true,

View File

@@ -2,7 +2,7 @@
"Version": 16,
"Title": "Wolfenstein 2D",
"Author": "id Software",
"Description": "You're William J. \"B.J.\" Blazkowicz, the Allies' bad boy of espionage and a terminal action seeker. Your mission was to infiltrate the Nazi fortress Castle Hollehammer and find the plans for Operation Eisenfaust (Iron Fist), the Nazi's blueprint for building the perfect army. Rumors are that deep within Castle Hollehammer the diabolical Dr. Schabbs has perfected a technique for building a fierce army from the bodies of the dead. It's so far removed from reality that it would seem silly if it wasn't so sick. But what if it were true?",
"Description": "",
"Ammo": true,
"WeaponPersist": true,
"SkipWeaponMenu": true,

View File

@@ -1,7 +1,11 @@
set(CW_SOURCES audio.c audio_sod.c audio_wl1.c audio_wl6.c cwolfmap.c expand.c vswap.c mame/fmopl.c)
set(CWHEADERS AUDIOSOD.H AUDIOWL1.H audiowl6.h audio.h audio_sod.h audio_wl1.h audio_wl6.h common.h cwolfmap.h expand.h vswap.h mame/fmopl.h)
set(CW_SOURCES audio.c audio_bs6.c audio_n3d.c audio_sod.c audio_wl1.c audio_wl6.c cwolfmap.c expand.c n3d.c vswap.c mame/fmopl.c)
set(CWHEADERS audiobs6.h audion3d.h AUDIOSOD.H AUDIOWL1.H audiowl6.h audio.h audio_bs6.h audio_n3d.h audio_sod.h audio_wl1.h audio_wl6.h common.h cwolfmap.h expand.h n3d.h vswap.h mame/fmopl.h)
add_subdirectory(wad)
add_subdirectory(zip)
add_library(cwolfmap STATIC ${CW_SOURCES} ${CWHEADERS})
target_link_libraries(cwolfmap wad zip)
if(NOT WIN32)
target_link_libraries(cwolfmap m)
endif()

View File

@@ -3,6 +3,8 @@
#include <stdio.h>
#include <stdlib.h>
#include "audio_bs6.h"
#include "audio_n3d.h"
#include "audio_sod.h"
#include "audio_wl1.h"
#include "audio_wl6.h"
@@ -176,6 +178,13 @@ int CWAudioLoadAudioT(CWAudio *audio, const CWMapType type, const char *path)
case CWMAPTYPE_SOD:
CWAudioSODLoadAudioT(audio);
break;
case CWMAPTYPE_BS1:
case CWMAPTYPE_BS6:
CWAudioBS6LoadAudioT(audio);
break;
case CWMAPTYPE_N3D:
CWAudioN3DLoadAudioT(audio);
break;
default:
fprintf(stderr, "Unknown map type\n");
err = -1;
@@ -194,6 +203,7 @@ void CWAudioFree(CWAudio *audio)
{
CWAudioHeadFree(&audio->head);
free(audio->data);
WAD_Close(audio->wad);
}
int CWAudioGetAdlibSoundRaw(
@@ -292,90 +302,103 @@ bail:
}
int CWAudioGetMusic(
const CWAudio *audio, const int idx, char **data, size_t *len)
CWAudio *audio, const CWMapType type, const int idx, char **data,
size_t *len)
{
*data = NULL;
*len = 0;
const char *rawData;
size_t rawLen;
int err = CWAudioGetMusicRaw(audio, idx, &rawData, &rawLen);
if (err != 0)
{
goto bail;
}
if (rawLen == 0)
{
goto bail;
}
int err = 0;
for (int i = 0; i < OPL_CHANNELS; i++)
if (type == CWMAPTYPE_N3D)
{
AlSetChanInst(&ChannelRelease, i);
}
// Measure length of music
const uint16_t *sqHack = (const uint16_t *)rawData;
int sqHackLen;
if (*sqHack == 0)
{
// LumpLength?
sqHackLen = (int)rawLen;
wadentry_t *entry = WAD_GetEntry(audio->wad, idx);
*data = malloc(entry->length);
*len = entry->length;
err = WAD_GetEntryData(audio->wad, entry, (unsigned char *)*data);
}
else
{
sqHackLen = *sqHack++;
}
const uint16_t *sqHackPtr = sqHack;
int sqHackTime = 0;
int alTimeCount;
for (alTimeCount = 0; sqHackLen > 0; alTimeCount++)
{
do
const char *rawData;
size_t rawLen;
err = CWAudioGetMusicRaw(audio, idx, &rawData, &rawLen);
if (err != 0)
{
if (sqHackTime > alTimeCount)
break;
sqHackTime = alTimeCount + *(sqHackPtr + 1);
sqHackPtr += 2;
sqHackLen -= 4;
} while (sqHackLen > 0);
}
// Decode music
// 2 bytes per sample (16-bit audio fmt)
*len = alTimeCount * SAMPLES_PER_MUSIC_TICK * MUSIC_AUDIO_CHANNELS * 2;
*data = malloc(*len);
int16_t *stream16 = (int16_t *)*data;
sqHack = (const uint16_t *)rawData;
if (*sqHack == 0)
{
// LumpLength?
sqHackLen = (int)rawLen;
}
else
{
sqHackLen = *sqHack++;
}
sqHackPtr = sqHack;
sqHackTime = 0;
for (alTimeCount = 0; sqHackLen > 0; alTimeCount++)
{
do
goto bail;
}
if (rawLen == 0)
{
if (sqHackTime > alTimeCount)
break;
sqHackTime = alTimeCount + *(sqHackPtr + 1);
alOut(
*(const uint8_t *)sqHackPtr,
*(((const uint8_t *)sqHackPtr) + 1));
sqHackPtr += 2;
sqHackLen -= 4;
} while (sqHackLen > 0);
goto bail;
}
YM3812UpdateOne(oplChip, stream16, SAMPLES_PER_MUSIC_TICK);
for (int i = 0; i < OPL_CHANNELS; i++)
{
AlSetChanInst(&ChannelRelease, i);
}
stream16 += SAMPLES_PER_MUSIC_TICK * MUSIC_AUDIO_CHANNELS;
// Measure length of music
const uint16_t *sqHack = (const uint16_t *)rawData;
int sqHackLen;
if (*sqHack == 0)
{
// LumpLength?
sqHackLen = (int)rawLen;
}
else
{
sqHackLen = *sqHack++;
}
const uint16_t *sqHackPtr = sqHack;
int sqHackTime = 0;
int alTimeCount;
for (alTimeCount = 0; sqHackLen > 0; alTimeCount++)
{
do
{
if (sqHackTime > alTimeCount)
break;
sqHackTime = alTimeCount + *(sqHackPtr + 1);
sqHackPtr += 2;
sqHackLen -= 4;
} while (sqHackLen > 0);
}
// Decode music
// 2 bytes per sample (16-bit audio fmt)
*len = alTimeCount * SAMPLES_PER_MUSIC_TICK * MUSIC_AUDIO_CHANNELS * 2;
*data = malloc(*len);
int16_t *stream16 = (int16_t *)*data;
sqHack = (const uint16_t *)rawData;
if (*sqHack == 0)
{
// LumpLength?
sqHackLen = (int)rawLen;
}
else
{
sqHackLen = *sqHack++;
}
sqHackPtr = sqHack;
sqHackTime = 0;
for (alTimeCount = 0; sqHackLen > 0; alTimeCount++)
{
do
{
if (sqHackTime > alTimeCount)
break;
sqHackTime = alTimeCount + *(sqHackPtr + 1);
alOut(
*(const uint8_t *)sqHackPtr,
*(((const uint8_t *)sqHackPtr) + 1));
sqHackPtr += 2;
sqHackLen -= 4;
} while (sqHackLen > 0);
YM3812UpdateOne(oplChip, stream16, SAMPLES_PER_MUSIC_TICK);
stream16 += SAMPLES_PER_MUSIC_TICK * MUSIC_AUDIO_CHANNELS;
}
}
return err;

View File

@@ -29,7 +29,8 @@ int CWAudioGetAdlibSound(
int CWAudioGetMusicRaw(
const CWAudio *audio, const int i, const char **data, size_t *len);
int CWAudioGetMusic(
const CWAudio *audio, const int i, char **data, size_t *len);
CWAudio *audio, const CWMapType type, const int idx, char **data,
size_t *len);
typedef enum
{

View File

@@ -0,0 +1,146 @@
// Contains code from bstone
// Copyright (c) 1992-2013 Apogee Entertainment, LLC
// Copyright(c) 2013 - 2022 Boris I.Bendovsky(bibendovsky @hotmail.com) and
// Contributors SPDX - License - Identifier : GPL - 2.0 - or -later
#include "audio_bs6.h"
#include "audiobs6.h"
void CWAudioBS6LoadAudioT(CWAudio *audio)
{
/*
if (assets_info.is_aog())
{
THEME_MUS = 16;
LASTMUSIC = 19;
}
else
{
THEME_MUS = 20;
LASTMUSIC = 21;
}
*/
audio->nSound = LASTSOUND;
audio->nMusic = LASTMUSIC;
audio->startAdlibSounds = STARTADLIBSOUNDS;
audio->startMusic = STARTMUSIC;
}
// https://github.com/bibendovsky/bstone/blob/46c9b7b146e57321fad87e1b3985a3d3e829bae7/src/3d_play.cpp#L204
// TODO: PS songs
static const int16_t songs[] = {
// Episode 1
INCNRATN_MUS, // secret1
DRKHALLA_MUS,
JUNGLEA_MUS,
RACSHUFL_MUS,
DRKHALLA_MUS,
HIDINGA_MUS,
JUNGLEA_MUS,
RACSHUFL_MUS,
HIDINGA_MUS,
DRKHALLA_MUS,
INCNRATN_MUS, // secret2
// Episode 2
FREEDOMA_MUS,
DRKHALLA_MUS,
STRUTA_MUS,
INTRIGEA_MUS,
MEETINGA_MUS,
DRKHALLA_MUS,
INCNRATN_MUS,
RACSHUFL_MUS,
JUNGLEA_MUS,
GENEFUNK_MUS,
THEME_MUS,
// Episode 3
LEVELA_MUS,
HIDINGA_MUS,
STRUTA_MUS,
THEME_MUS,
RACSHUFL_MUS,
INCNRATN_MUS,
GOLDA_MUS,
JUNGLEA_MUS,
DRKHALLA_MUS,
THEWAYA_MUS,
FREEDOMA_MUS,
// Episode 4
HIDINGA_MUS,
DRKHALLA_MUS,
GENEFUNK_MUS,
JUNGLEA_MUS,
INCNRATN_MUS,
GOLDA_MUS,
HIDINGA_MUS,
JUNGLEA_MUS,
DRKHALLA_MUS,
THEWAYA_MUS,
RUMBAA_MUS,
// Episode 5
RACSHUFL_MUS,
SEARCHNA_MUS,
JUNGLEA_MUS,
HIDINGA_MUS,
GENEFUNK_MUS,
MEETINGA_MUS,
S2100A_MUS,
THEME_MUS,
INCNRATN_MUS,
DRKHALLA_MUS,
THEWAYA_MUS,
// Episode 6
TIMEA_MUS,
RACSHUFL_MUS,
GENEFUNK_MUS,
HIDINGA_MUS,
S2100A_MUS,
THEME_MUS,
THEWAYA_MUS,
JUNGLEA_MUS,
MEETINGA_MUS,
DRKHALLA_MUS,
INCNRATN_MUS,
};
int CWAudioBS6GetLevelMusic(const int level)
{
return songs[level];
}
int CWAudioBS6GetSong(const CWSongType song)
{
/*
if (assets_info.is_ps())
{
MENUSONG = LASTLAFF_MUS;
ROSTER_MUS = HISCORE_MUS;
TEXTSONG = TOHELL_MUS;
TITLE_LOOP_MUSIC = PLOT_MUS;
}
else
{
MENUSONG = MEETINGA_MUS;
ROSTER_MUS = LEVELA_MUS;
TEXTSONG = RUMBAA_MUS;
TITLE_LOOP_MUSIC = GOLDA_MUS;
}
*/
switch (song)
{
case SONG_INTRO:
return GOLDA_MUS;
case SONG_MENU:
return MEETINGA_MUS;
case SONG_END:
return -1; // blake stone has no end level music
case SONG_ROSTER:
return RUMBAA_MUS;
case SONG_VICTORY:
return LEVELA_MUS;
}
return -1;
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include "audio.h"
void CWAudioBS6LoadAudioT(CWAudio *audio);
int CWAudioBS6GetLevelMusic(const int level);
int CWAudioBS6GetSong(const CWSongType song);

View File

@@ -0,0 +1,53 @@
#include "audio_n3d.h"
#include "audion3d.h"
void CWAudioN3DLoadAudioT(CWAudio *audio)
{
audio->nSound = LASTSOUND;
audio->nMusic = LASTMUSIC;
audio->startAdlibSounds = STARTADLIBSOUNDS;
audio->startMusic = STARTMUSIC;
}
int CWAudioN3DLoadAudioWAD(CWAudio *audio, const char *path)
{
int err = 0;
audio->wad = WAD_Open(path);
if (audio->wad == NULL)
{
err = -1;
fprintf(stderr, "Failed to read %s\n", path);
goto bail;
}
bail:
return err;
}
static const int16_t songs[] = {
SONG1_MUS, ALLGOOD_MUS, SONG7_MUS, SONG3_MUS, SONG1_MUS, ALLGOOD_MUS,
SONG7_MUS, SONG4_MUS, SONG3_MUS, SONG1_MUS, SONG7_MUS, SONG6_MUS,
SONG4_MUS, ALLGOOD_MUS, SONG3_MUS, SONG7_MUS, SONG8_MUS, SONG1_MUS,
SONG6_MUS, SONG4_MUS, HAPPYSNG_MUS, SONG7_MUS, SONG11_MUS, ALLGOOD_MUS,
SONG3_MUS, SONG8_MUS, SONG6_MUS, SONG7_MUS, SONG9_MUS, ALLGOOD_MUS};
int CWAudioN3DGetLevelMusic(const int level)
{
return songs[level];
}
int CWAudioN3DGetSong(const CWSongType song)
{
switch (song)
{
case SONG_INTRO:
return SONG1_MUS;
case SONG_MENU:
return SONG9_MUS;
case SONG_END:
return FEEDTIME_MUS;
case SONG_ROSTER:
return SONG11_MUS;
case SONG_VICTORY:
return ALLGOOD_MUS;
}
return -1;
}

View File

@@ -0,0 +1,7 @@
#pragma once
#include "audio.h"
void CWAudioN3DLoadAudioT(CWAudio *audio);
int CWAudioN3DLoadAudioWAD(CWAudio *audio, const char *path);
int CWAudioN3DGetLevelMusic(const int level);
int CWAudioN3DGetSong(const CWSongType song);

View File

@@ -0,0 +1,189 @@
/*
BStone: A Source port of
Blake Stone: Aliens of Gold and Blake Stone: Planet Strike
Copyright (c) 1992-2013 Apogee Entertainment, LLC
Copyright (c) 2013-2015 Boris I. Bendovsky (bibendovsky@hotmail.com)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef BSTONE_AUDIO_INCLUDED
#define BSTONE_AUDIO_INCLUDED
//
// Base offsets
//
#define STARTPCSOUNDS 0
#define STARTADLIBSOUNDS 100
#define STARTDIGISOUNDS 200
#define STARTMUSIC 300
const int16_t NUMSOUNDS = 100;
//
// Sound names & indexes
//
const int16_t HITWALLSND = 0;
const int16_t TERM_TYPESND = 1;
const int16_t GETPISTOLSND = 2;
const int16_t LIQUIDDIESND = 3;
const int16_t MOVEGUN2SND = 4;
const int16_t MOVEGUN1SND = 5;
const int16_t NOWAYSND = 6;
const int16_t SCOUT_ALERTSND = 7;
const int16_t GURNEYSND = 8;
const int16_t PLAYERDEATHSND = 9;
const int16_t CONCESSIONSSND = 10;
const int16_t ATKIONCANNONSND = 11;
const int16_t GETKEYSND = 12;
const int16_t WARPOUTSND = 13;
const int16_t WARPINSND = 14;
const int16_t ROBOT_SERVOSND = 15;
const int16_t INFORMANTDEATHSND = 16;
const int16_t GOLDSTERNHALTSND = 17;
const int16_t OPENDOORSND = 18;
const int16_t CLOSEDOORSND = 19;
const int16_t GETDETONATORSND = 20;
const int16_t HALTSND = 21;
const int16_t RENTDEATH2SND = 22;
const int16_t ATKAUTOCHARGESND = 23;
const int16_t ATKCHARGEDSND = 24;
const int16_t RADAR_POWERUPSND = 25;
const int16_t ATKBURSTRIFLESND = 26;
const int16_t VITAL_GONESND = 27;
const int16_t SHOOTDOORSND = 28;
const int16_t RENTDEATH1SND = 29;
const int16_t GETBURSTRIFLESND = 30;
const int16_t GETAMMOSND = 31;
const int16_t SHOOTSND = 32;
const int16_t HEALTH1SND = 33;
const int16_t HEALTH2SND = 34;
const int16_t BONUS1SND = 35;
const int16_t BONUS2SND = 36;
const int16_t BONUS3SND = 37;
const int16_t GETIONCANNONSND = 38;
const int16_t ESCPRESSEDSND = 39;
const int16_t ELECAPPEARSND = 40;
const int16_t EXTRA_MANSND = 41;
const int16_t ELEV_BUTTONSND = 42;
const int16_t INTERROGATESND = 43;
const int16_t BONUS5SND = 44;
const int16_t BONUS4SND = 45;
const int16_t PUSHWALLSND = 46;
const int16_t TERM_BEEPSND = 47;
const int16_t ROLL_SCORESND = 48;
const int16_t TURRETSND = 49;
const int16_t EXPLODE1SND = 50;
const int16_t __UNUSED_51__SND = 51;
const int16_t SWATDIESND = 52;
const int16_t GGUARDHALTSND = 53;
const int16_t EXPLODE2SND = 54;
const int16_t BLUEBOYHALTSND = 55;
const int16_t PROGUARDDEATHSND = 56;
const int16_t DOGBOYHALTSND = 57;
const int16_t ENGINE_THRUSTSND = 58;
const int16_t SCANHALTSND = 59;
const int16_t GETCANNONSND = 60;
const int16_t LCANHALTSND = 61;
const int16_t PROHALTSND = 62;
const int16_t GGUARDDEATHSND = 63;
const int16_t BLUEBOYDEATHSND = 64;
const int16_t GOLDSTERNLAUGHSND = 65;
const int16_t SCIENTISTHALTSND = 66;
const int16_t SCIENTISTDEATHSND = 67;
const int16_t DOGBOYDEATHSND = 68;
const int16_t H_BEATSND = 69;
const int16_t SWATHALTSND = 70;
const int16_t SCANDEATHSND = 71;
const int16_t LCANDEATHSND = 72;
const int16_t INFORMDEATH2SND = 73;
const int16_t INFORMDEATH3SND = 74;
const int16_t GURNEYDEATHSND = 75;
const int16_t PRODEATH2SND = 76;
const int16_t PRODEATH3SND = 77; // AOG
const int16_t SWATDEATH2SND = 78;
const int16_t LCANBREAKSND = 79;
const int16_t SCANBREAKSND = 80;
const int16_t HTECHDOOROPENSND = 81;
const int16_t HTECHDOORCLOSESND = 82;
const int16_t ELECARCDAMAGESND = 83;
const int16_t PODHATCHSND = 84;
const int16_t ELECTSHOTSND = 85;
const int16_t ELECDIESND = 86;
const int16_t ATKGRENADESND = 87;
const int16_t CLAWATTACKSND = 88;
const int16_t PUNCHATTACKSND = 89;
const int16_t SPITATTACKSND = 90;
const int16_t PODDEATHSND = 91;
const int16_t PODHALTSND = 92;
const int16_t SWATDEATH3SND = 93; // AOG
const int16_t SCIDEATH2SND = 94;
const int16_t SCIDEATH3SND = 95;
const int16_t GOTTOKENSND = 96;
const int16_t SWITCHSND = 97;
const int16_t STATS1SND = 98;
const int16_t STATS2SND = 99;
#define LASTSOUND 100
//
// Music names & indexes (AOG)
//
#define S2100A_MUS 0
#define GOLDA_MUS 1
#define APOGFNFM_MUS 2
#define DRKHALLA_MUS 3
#define FREEDOMA_MUS 4
#define GENEFUNK_MUS 5
#define TIMEA_MUS 6
#define HIDINGA_MUS 7
#define INCNRATN_MUS 8
#define JUNGLEA_MUS 9
#define LEVELA_MUS 10
#define MEETINGA_MUS 11
#define STRUTA_MUS 12
#define RACSHUFL_MUS 13
#define RUMBAA_MUS 14
#define SEARCHNA_MUS 15
#define THEME_MUS 16
#define THEWAYA_MUS 17
#define INTRIGEA_MUS 18
#define LASTMUSIC 19
//
// Music names & indexes (PS)
//
#define CATACOMB_MUS 0
#define STICKS_MUS 1
#define PLOT_MUS 3
#define CIRCLES_MUS 4
#define LASTLAFF_MUS 5
#define TOHELL_MUS 6
#define FORTRESS_MUS 7
#define GIVING_MUS 8
#define HARTBEAT_MUS 9
#define LURKING_MUS 10
#define MAJMIN_MUS 11
#define VACCINAP_MUS 12
#define DARKNESS_MUS 13
#define MONASTRY_MUS 14
#define TOMBP_MUS 15
#define TIME_MUS 16
#define MOURNING_MUS 17
#define SERPENT_MUS 18
#define HISCORE_MUS 19
#endif // BSTONE_AUDIO_INCLUDED

View File

@@ -0,0 +1,26 @@
#pragma once
// TODO: figure out values
//
// Base offsets
//
#define STARTPCSOUNDS 0
#define STARTADLIBSOUNDS 100
#define STARTDIGISOUNDS 200
#define STARTMUSIC 300
#define LASTSOUND 100
#define SONG1_MUS 0
#define ALLGOOD_MUS 1
#define SONG3_MUS 2
#define SONG4_MUS 3
#define FEEDTIME_MUS 4
#define SONG6_MUS 5
#define SONG7_MUS 6
#define SONG8_MUS 7
#define SONG9_MUS 8
#define HAPPYSNG_MUS 9
#define SONG11_MUS 10
#define LASTMUSIC 11

View File

@@ -1,12 +1,16 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include "wad/wad.h"
typedef enum
{
CWMAPTYPE_WL1,
CWMAPTYPE_WL6,
CWMAPTYPE_SOD,
CWMAPTYPE_BS1,
CWMAPTYPE_BS6,
CWMAPTYPE_N3D,
CWMAPTYPE_UNKNOWN,
} CWMapType;
@@ -24,4 +28,5 @@ typedef struct
int startAdlibSounds;
int startMusic;
char *data;
wad_t *wad;
} CWAudio;

View File

@@ -16,9 +16,12 @@
#include <unistd.h>
#endif
#include "audio_n3d.h"
#include "audiowl6.h"
#include "expand.h"
#include "n3d.h"
// TODO: use map header magic value
#define MAGIC 0xABCD
#define PATH_MAX 4096
@@ -75,6 +78,27 @@ CWMapType CWGetType(
return CWMAPTYPE_SOD;
}
}
sprintf(pathBuf, "%s/MAPHEAD.BS6", path);
if (access(pathBuf, F_OK) != -1)
{
if (ext && ext1)
*ext = *ext1 = "BS6";
return CWMAPTYPE_BS6;
}
sprintf(pathBuf, "%s/MAPHEAD.BS1", path);
if (access(pathBuf, F_OK) != -1)
{
if (ext && ext1)
*ext = *ext1 = "BS1";
return CWMAPTYPE_BS1;
}
sprintf(pathBuf, "%s/maphead.n3d", path);
if (access(pathBuf, F_OK) != -1)
{
if (ext && ext1)
*ext = *ext1 = "n3d";
return CWMAPTYPE_N3D;
}
return CWMAPTYPE_UNKNOWN;
}
@@ -111,12 +135,40 @@ int CWLoad(CWolfMap *map, const char *path, const int spearMission)
}
_TRY_LOAD("MAPHEAD", LoadMapHead, map, pathBuf);
_TRY_LOAD("GAMEMAPS", LoadMapData, map, pathBuf);
if (map->type == CWMAPTYPE_BS1 || map->type == CWMAPTYPE_BS6)
{
_TRY_LOAD("MAPTEMP", LoadMapData, map, pathBuf);
}
else
{
_TRY_LOAD("GAMEMAPS", LoadMapData, map, pathBuf);
}
_TRY_LOAD("AUDIOHED", CWAudioLoadHead, &map->audio.head, pathBuf);
_TRY_LOAD("AUDIOT", CWAudioLoadAudioT, &map->audio, map->type, pathBuf);
if (map->type == CWMAPTYPE_N3D)
{
// N3D stores music as ogg files in wad
sprintf(pathBuf, "%s/noah3d.wad", path);
loadErr = CWAudioN3DLoadAudioWAD(&map->audio, pathBuf);
if (loadErr != 0)
{
err = loadErr;
}
// Load custom level data
sprintf(pathBuf, "%s/noah3d.pk3", path);
char *languageBuf = CWN3DLoadLanguageEnu(pathBuf);
for (int i = 0; i < map->nLevels; i++)
{
map->levels[i].description =
CWLevelN3DLoadDescription(languageBuf, i);
}
free(languageBuf);
}
_TRY_LOAD("VSWAP", CWVSwapLoad, &map->vswap, pathBuf);
bail:
@@ -154,7 +206,9 @@ bail:
static void LevelsFree(CWolfMap *map);
static int LoadLevel(CWLevel *level, const unsigned char *data, const int off);
static int LoadLevel(
const CWolfMap *map, CWLevel *level, const unsigned char *data,
const int off);
static int LoadMapData(CWolfMap *map, const char *path)
{
int err = 0;
@@ -187,7 +241,7 @@ static int LoadMapData(CWolfMap *map, const char *path)
CWLevel *lPtr = map->levels;
for (const int32_t *ptr = &map->mapHead.ptr[0]; *ptr > 0; ptr++, lPtr++)
{
err = LoadLevel(lPtr, buf, *ptr);
err = LoadLevel(map, lPtr, buf, *ptr);
if (err != 0)
{
goto bail;
@@ -207,12 +261,16 @@ bail:
return err;
}
static int LoadPlane(
CWPlane *plane, const unsigned char *data, const uint32_t off,
unsigned char *buf, const int bufSize);
static int LoadLevel(CWLevel *level, const unsigned char *data, const int off)
const CWolfMap *map, CWPlane *plane, const unsigned char *data,
const uint32_t off, unsigned char *buf, const int bufSize);
// https://moddingwiki.shikadi.net/wiki/GameMaps_Format#Level_headers
static int LoadLevel(
const CWolfMap *map, CWLevel *level, const unsigned char *data,
const int off)
{
int err = 0;
unsigned char *buf = NULL;
level->description = NULL;
memcpy(&level->header, data + off, sizeof(level->header));
const int bufSize =
@@ -220,8 +278,14 @@ static int LoadLevel(CWLevel *level, const unsigned char *data, const int off)
buf = malloc(bufSize);
for (int i = 0; i < NUM_PLANES; i++)
{
const int32_t plen = *(&level->header.lenPlane0 + i);
if (plen <= 0)
{
memset(&level->planes[i], 0, sizeof level->planes[i]);
continue;
}
const uint32_t poff = *(&level->header.offPlane0 + i);
err = LoadPlane(&level->planes[i], data, poff, buf, bufSize);
err = LoadPlane(map, &level->planes[i], data, poff, buf, bufSize);
if (err != 0)
{
goto bail;
@@ -251,8 +315,8 @@ bail:
return err;
}
static int LoadPlane(
CWPlane *plane, const unsigned char *data, const uint32_t off,
unsigned char *buf, const int bufSize)
const CWolfMap *map, CWPlane *plane, const unsigned char *data,
const uint32_t off, unsigned char *buf, const int bufSize)
{
int err = 0;
@@ -264,7 +328,9 @@ static int LoadPlane(
ExpandCarmack(data + off, buf);
plane->len = bufSize;
plane->plane = malloc(bufSize);
ExpandRLEW(buf, (unsigned char *)plane->plane, MAGIC);
const bool hasFinalLength =
map->type != CWMAPTYPE_BS6 && map->type != CWMAPTYPE_BS1;
ExpandRLEW(buf, (unsigned char *)plane->plane, MAGIC, hasFinalLength);
bail:
return err;
@@ -286,6 +352,10 @@ void CWCopy(CWolfMap *dst, const CWolfMap *src)
dst->levels[i].planes[j].plane, src->levels[i].planes[j].plane,
len);
}
if (src->levels[i].description)
{
dst->levels[i].description = strdup(src->levels[i].description);
}
}
const size_t audioHeadLen = dst->audio.head.nOffsets * sizeof(uint32_t);
dst->audio.head.offsets = malloc(audioHeadLen);
@@ -299,6 +369,7 @@ void CWCopy(CWolfMap *dst, const CWolfMap *src)
const size_t vswapSoundsLen = dst->vswap.nSounds * sizeof(CWVSwapSound);
dst->vswap.sounds = malloc(vswapSoundsLen);
memcpy(dst->vswap.sounds, src->vswap.sounds, vswapSoundsLen);
// TODO: copy wad
}
void CWFree(CWolfMap *map)
@@ -328,6 +399,119 @@ static void LevelFree(CWLevel *level)
{
free(level->planes[i].plane);
}
free(level->description);
}
const char *CWGetDescription(CWolfMap *map, const int spearMission)
{
switch (map->type)
{
case CWMAPTYPE_BS1:
case CWMAPTYPE_BS6: // fallthrough
return "You're pitted against Dr. Pyrus Goldfire. He's found a way to "
"replicate pure gold, which he's using to fund his maniacal "
"plan. Goldfire has built six highly-secure, futuristic "
"locations where his creations are being hatched. It's up to "
"you to penetrate his security and stop him at all costs.";
case CWMAPTYPE_N3D:
return "It's been a long journey. In just a few days, the ark doors "
"will open and Noah, his family & the animals will be back on "
"dry land. But the animals have become a bit restless and are "
"out of their cages. Camels, giraffes, monkeys, kangaroos and "
"more are wandering throughout the corridors of the ark. As "
"Noah, it's your job to regain order & get the animals to "
"sleep until you leave the ark. Your only tool to accomplish "
"this is the food you brought aboard the ark. Can it be done? "
"You bet! But how?";
case CWMAPTYPE_SOD:
switch (spearMission)
{
case 1:
return "It's World War II and you are B.J. Blazkowicz, the "
"Allies' "
"most valuable agent. In the midst of the German "
"Blitzkrieg, "
"the Spear that pierced the side of Christ is taken from "
"Versailles by the Nazis and secured in the impregnable "
"Castle "
"Wolfenstein. According to legend, no man can be defeated "
"when "
"he has the Spear. Hitler believes himself to be "
"invincible "
"with the power of the Spear as his brutal army sweeps "
"across "
"Europe.\n\nYour mission is to infiltrate the heavily "
"guarded "
"Nazi stronghold and recapture the Spear from an already "
"unbalanced Hitler. The loss of his most coveted weapon "
"could "
"push him over the edge. It could also get you ripped to "
"pieces.";
case 2:
return "Six weeks after the Spear of Destiny has been brought out "
"of enemy hands, the Axis mounts a successful commando "
"raid to recover it! After a bloody battle and narrow "
"escape, it's taken to the Nazis' Secret Scandinavian "
"Base, excavated from the solid rock of a fjord. The "
"fortress is said to be impregnable!";
case 3:
return "As the Allies' top agent, you face your toughest "
"challenge yet! Learning from his past mistakes, Hitler "
"has expanded his subterranean command bunker beneath the "
"chancellery in Berlin so that he can keep the Spear of "
"Destiny nearby and well-guarded!\n\nCalling upon the dark "
"forces of the occult, Hitler can see into the future and "
"obtain the plans to future weapon systems!";
}
break;
case CWMAPTYPE_WL1:
return "Captured in your attempt to grab the secret plans, you "
"were taken to the Nazi prison Castle Wolfenstein for "
"questioning and eventual execution. Now for twelve long "
"days you've been imprisoned beneath the castle fortress. "
"Just beyond your cell door sits a lone thick-necked Nazi "
"guard. He assisted an SS Dentist / Mechanic in an attempt "
"to jump start your tonsils earlier that morning. You're "
"at your breaking point! Quivering on the floor you beg "
"for medical assistance in return for information. His "
"face hints a smug grin of victory as he reaches for his "
"keys. He opens the door, tumblers in the lock echo "
"through the corridors and the door squeaks open. HIS "
"MISTAKE!\n\nA single kick to his knee sends him to the "
"floor. Giving him your version of the victory sign, you "
"grab his knife and quickly finish the job. You stand over "
"the guard's fallen body, grabbing frantically for his "
"gun. You're not sure if the other guards heard his "
"muffled scream. Deep in the belly of a Nazi dungeon, you "
"must escape. This desperate act has sealed your fate-get "
"out or die trying.";
case CWMAPTYPE_WL6:
return "You're William J. \"B.J.\" Blazkowicz, the Allies' bad "
"boy of espionage and a terminal action seeker. Your "
"mission was to infiltrate the Nazi fortress Castle "
"Hollehammer and find the plans for Operation Eisenfaust "
"(Iron Fist), the Nazi's blueprint for building the "
"perfect army. Rumors are that deep within Castle "
"Hollehammer the diabolical Dr. Schabbs has perfected a "
"technique for building a fierce army from the bodies of "
"the dead. It's so far removed from reality that it would "
"seem silly if it wasn't so sick. But what if it were "
"true?";
default:
break;
}
return NULL;
}
int CWGetAudioSampleRate(const CWolfMap *map)
{
switch (map->type)
{
case CWMAPTYPE_N3D:
return 11025;
default:
return 7042;
}
}
// http://gaarabis.free.fr/_sites/specs/wlspec_index.html
@@ -336,7 +520,7 @@ uint16_t CWLevelGetCh(
const CWLevel *level, const int planeIndex, const int x, const int y)
{
const CWPlane *plane = &level->planes[planeIndex];
return plane->plane[y * level->header.height + x];
return plane->plane[y * level->header.width + x];
}
static const CWTile tileMap[] = {
@@ -432,7 +616,7 @@ static const CWTile tileMap[] = {
CWTILE_UNKNOWN,
CWTILE_UNKNOWN,
CWTILE_UNKNOWN,
CWTILE_UNKNOWN,
CWTILE_BACKGROUND,
// 90
CWTILE_DOOR_V,
CWTILE_DOOR_H,
@@ -441,8 +625,8 @@ static const CWTile tileMap[] = {
CWTILE_DOOR_SILVER_V,
CWTILE_DOOR_SILVER_H,
// 96-99
CWTILE_UNKNOWN,
CWTILE_UNKNOWN,
CWTILE_DOOR_V, // Doors to stairs
CWTILE_DOOR_H,
CWTILE_UNKNOWN,
CWTILE_UNKNOWN,
// 100
@@ -701,8 +885,8 @@ static const CWEntity entityMap[] = {
CWENT_PUSHWALL,
CWENT_ENDGAME,
// 100
CWENT_UNKNOWN,
CWENT_UNKNOWN,
CWENT_NEXT_LEVEL,
CWENT_SECRET_LEVEL,
CWENT_UNKNOWN,
CWENT_UNKNOWN,
CWENT_UNKNOWN,
@@ -738,8 +922,8 @@ static const CWEntity entityMap[] = {
CWENT_SS_MOVING_N,
CWENT_SS_MOVING_W,
CWENT_SS_MOVING_S,
CWENT_UNKNOWN,
CWENT_UNKNOWN,
CWENT_KERRY_KANGAROO,
CWENT_ERNIE_ELEPHANT,
CWENT_UNKNOWN,
CWENT_UNKNOWN,
CWENT_DOG_E,

View File

@@ -38,6 +38,7 @@ typedef struct
CWLevelHead header;
CWPlane planes[NUM_PLANES];
bool hasPlayerSpawn;
char *description;
} CWLevel;
typedef struct
@@ -57,6 +58,10 @@ int CWLoad(CWolfMap *map, const char *path, const int spearMission);
void CWCopy(CWolfMap *dst, const CWolfMap *src);
void CWFree(CWolfMap *map);
const char *CWGetDescription(CWolfMap *map, const int spearMission);
int CWGetAudioSampleRate(const CWolfMap *map);
typedef enum
{
CWTILE_WALL,
@@ -70,6 +75,7 @@ typedef enum
CWTILE_ELEVATOR_H,
CWTILE_SECRET_EXIT,
CWTILE_AREA,
CWTILE_BACKGROUND,
CWTILE_UNKNOWN,
} CWTile;
@@ -134,6 +140,8 @@ typedef enum
CWENT_SPEAR,
CWENT_PUSHWALL,
CWENT_ENDGAME,
CWENT_NEXT_LEVEL,
CWENT_SECRET_LEVEL,
CWENT_GHOST,
CWENT_ANGEL,
CWENT_DEAD_GUARD,
@@ -203,6 +211,9 @@ typedef enum
CWENT_PACMAN_GHOST_ROSE,
CWENT_PACMAN_GHOST_BLUE,
CWENT_KERRY_KANGAROO,
CWENT_ERNIE_ELEPHANT,
CWENT_UNKNOWN,
} CWEntity;

View File

@@ -92,10 +92,17 @@ void ExpandCarmack(const unsigned char *in, unsigned char *out)
}
}
void ExpandRLEW(const unsigned char *in, unsigned char *out, const WORD rlewTag)
// https://moddingwiki.shikadi.net/wiki/Id_Software_RLEW_compression
void ExpandRLEW(
const unsigned char *in, unsigned char *out, const WORD rlewTag,
const bool hasFinalLength)
{
const DWORD length = ReadLittleShort((const BYTE *)in);
in += 2;
DWORD length = 64 * 64 * 2; // width*height*<bytes in 16bit>
if (hasFinalLength)
{
length = ReadLittleShort((const BYTE *)in);
in += 2;
}
const unsigned char *const end = out + length;
while (out < end)
@@ -110,7 +117,7 @@ void ExpandRLEW(const unsigned char *in, unsigned char *out, const WORD rlewTag)
WORD count = ReadLittleShort((const BYTE *)(in + 2));
WORD input = ReadLittleShort((const BYTE *)(in + 4));
in += 6;
while (count-- > 0)
for (int i = 0; i < count; i++)
{
WriteLittleShort((BYTE *)out, input);
out += 2;

View File

@@ -1,4 +1,5 @@
#pragma once
#pragma once
#include <stdbool.h>
#include <stdint.h>
#define BYTE uint8_t
@@ -7,4 +8,5 @@
void ExpandCarmack(const unsigned char *in, unsigned char *out);
void ExpandRLEW(
const unsigned char *in, unsigned char *out, const WORD rlewTag);
const unsigned char *in, unsigned char *out, const WORD rlewTag,
const bool hasFinalLength);

103
src/cdogs/cwolfmap/n3d.c Normal file
View File

@@ -0,0 +1,103 @@
#include "n3d.h"
#include <stdlib.h>
#include "zip/zip.h"
#ifndef MIN
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#endif
char *CWN3DLoadLanguageEnu(const char *path)
{
char *buf = NULL;
struct zip_t *zip = zip_open(path, 0, 'r');
if (zip == NULL)
{
goto bail;
}
zip_entry_open(zip, "language.enu");
const size_t bufsize = zip_entry_size(zip);
buf = malloc(bufsize);
zip_entry_noallocread(zip, (void *)buf, bufsize);
bail:
zip_entry_close(zip);
zip_close(zip);
return buf;
}
static char *LoadLanguageEnuString(const char *buf, const char *key)
{
const char *start = buf;
char linebuf[1024];
while (start)
{
long long len = MIN(1024, strlen(start));
char *nl = strchr(start, '\n');
if (nl != NULL)
{
len = MIN(len, nl - start);
}
strncpy(linebuf, start, len);
linebuf[len] = '\0';
// Find entry lines
char *equals = strstr(linebuf, " = ");
if (equals != NULL)
{
// Key is now the start of the line
*equals = '\0';
if (strcmp(linebuf, key) == 0)
{
char *value = equals + strlen(" = \"");
char *endQuote = linebuf + len - strlen("\";");
*endQuote = '\0';
// Unescape newlines in the string
char *dst = value;
const char *src = value;
while (*src)
{
if (*src == '\\' && *(src + 1) == 'n')
{
*(dst++) = '\n';
src += 2;
}
else
{
*(dst++) = *(src++);
}
}
*dst = '\0';
return strdup(value);
}
}
if (nl == NULL)
{
break;
}
start = nl + 1;
}
return NULL;
}
char *CWLevelN3DLoadDescription(const char *buf, const int level)
{
switch (level)
{
case 0:
return LoadLanguageEnuString(buf, "NOAH_BRIEF_01");
case 3:
return LoadLanguageEnuString(buf, "NOAH_BRIEF_02");
case 7:
return LoadLanguageEnuString(buf, "NOAH_BRIEF_03");
case 12:
return LoadLanguageEnuString(buf, "NOAH_BRIEF_04");
case 17:
return LoadLanguageEnuString(buf, "NOAH_BRIEF_05");
case 23:
return LoadLanguageEnuString(buf, "NOAH_BRIEF_06");
}
return NULL;
}

7
src/cdogs/cwolfmap/n3d.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
// Load the noah3d.pak/language.enu file to char buffer, containing briefs and
// quizzes
char *CWN3DLoadLanguageEnu(const char *path);
char *CWLevelN3DLoadDescription(const char *buf, const int level);

View File

@@ -5,7 +5,7 @@
#include <stdlib.h>
#include <string.h>
// http://gaarabis.free.fr/_sites/specs/wlspec_index.html
// https://web.archive.org/web/20201206195550/http://gaarabis.free.fr/_sites/specs/wlspec_index.html
#define PATH_MAX 4096

View File

@@ -2,7 +2,6 @@
#include <stdint.h>
#include <string.h>
#define SND_RATE 7042
// Sounds are unsigned 8-bit mono PCM
#pragma pack(push, 1)

View File

@@ -0,0 +1,14 @@
set(WAD_SOURCES wad.c waderrno.c)
set(WAD_HEADERS wad.h wad_config.h waderrno.h)
if(MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -MP -W4 -WX -wd\"4057\" -wd\"4100\" -wd\"4267\" -wd\"4273\" -wd\"4706\"")
else()
add_definitions(
-fsigned-char
-Wall -W
-Wpointer-arith
-Wno-cast-qual -Wno-conversion -Wno-parentheses -Wno-pointer-sign -Wno-sign-compare -Wno-strict-prototypes -Wno-switch -Wno-unused-parameter)
endif()
add_library(wad STATIC ${WAD_SOURCES} ${WAD_HEADERS})

1966
src/cdogs/cwolfmap/wad/wad.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,536 @@
/*****************************************************************************
* Copyright (c) 2018 Matt Tropiano
* All rights reserved. This source and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
*****************************************************************************/
#ifndef __WAD_H__
#define __WAD_H__
#include <stdint.h>
#include <string.h>
#include <stdio.h>
// Important defines.
#define WADTYPE_IWAD 0x44415749
#define WADTYPE_PWAD 0x44415750
#define WADBUFFER_INITSIZE (1024 * 32)
#define WADENTRIES_INITSIZE 16
/**
* A WAD header structure (the start of all WAD files).
*/
typedef struct {
/** The magic number ("IWAD" or "PWAD"). */
uint32_t type;
/** The amount of entries in the WAD. */
int32_t entry_count;
/** The byte offset into the WAD for the entry list. */
int32_t entry_list_offset;
} wadheader_t;
/**
* A WAD entry.
*/
typedef struct {
/** Entry content offset into file. */
uint32_t offset;
/** Entry content length. */
int32_t length;
/** Entry name. */
unsigned char name[8]; // not null-terminated if all 8 are used!
} wadentry_t;
/**
* WAD implementation type.
* This determines how data is loaded and manipulated and what functions to call.
*/
typedef enum {
/** Unknown type - not initialized. */
WI_UNKNOWN,
/** Shallow entry map - preview only (no deep read, no write). */
WI_MAP,
/** Content and entries stored in memory. */
WI_BUFFER,
/** Content and entries read from open file (random access). */
WI_FILE,
} wadimpl_t;
/**
* A WAD abstraction.
*/
typedef struct {
/** Implementation type. */
wadimpl_t type;
/** Handle union. */
union {
/** If WI_FILE. */
FILE *file;
/** If WI_BUFFER. */
unsigned char *buffer;
} handle;
/** WAD header. */
wadheader_t header;
/** WAD entry list. */
wadentry_t **entries;
/** WAD entry list current capacity. */
int entries_capacity;
/** WAD buffer size (if buffer implementation). */
int buffer_size;
/** WAD buffer capacity (if buffer implementation). */
int buffer_capacity;
} wad_t;
/**
* A simple iterator abstraction for WADs.
*/
typedef struct {
/** Pointer to WAD. */
wad_t *wad;
/** Pointer to current entry. */
wadentry_t *entry;
/** Next index. */
int next;
/** Total count. */
int count;
} waditerator_t;
// ================ Common WAD Functions ====================
/**
* Opens an existing WAD file for random access.
* @param filename the file name to open.
* @return a newly-allocated wad_t (file implementation), or NULL on error.
*/
wad_t *WAD_Open(const char *filename);
/**
* Creates a new WAD file for random access.
* The file is created at the specified path.
* @param filename the file name to create.
* @return a newly-allocated wad_t (file implementation), or NULL on error.
*/
wad_t* WAD_Create(char *filename);
/**
* Opens an existing WAD file, but only skims for entry data.
* The file is not left open - no handle is kept.
* @param filename the file name to open.
* @return a newly-allocated wad_t (mapping implementation), or NULL on error.
*/
wad_t* WAD_OpenMap(char *filename);
/**
* Creates a WAD buffer in memory by loading the contents of an existing WAD file completely into memory.
* The file is not left open - no handle is kept.
* @param filename the file name to open.
* @return a newly-allocated wad_t (mapping implementation), or NULL on error.
*/
wad_t* WAD_OpenBuffer(char *filename);
/**
* Creates a WAD buffer in memory with a default initial content buffer size WADBUFFER_INITSIZE.
* WARNING: Buffers must be saved to disk, or they are not persisted anywhere!
* @return a newly-allocated wad_t (buffer implementation), or NULL on error.
*/
wad_t* WAD_CreateBuffer(void);
/**
* Creates a WAD buffer in memory with a specific initial content buffer size.
* @param size the initial size, in bytes.
* @return a newly-allocated wad_t (mapping implementation), or NULL on error.
*/
wad_t* WAD_CreateBufferInit(int size);
/**
* Gets the amount of entries that this WAD contains.
* @param wad the pointer to the open WAD.
* @return the amount of entries or -1 on error.
*/
#define WAD_EntryCount(w) ((int)((w)->header.entry_count))
/**
* Commits changes to WAD entries that would not ordinarily be
* detected by other functions that manipulate entries.
* Most WAD_* functions call this - you only need to call this
* if you edit the entry list pointers or their values explicitly.
* @param wad the pointer to the open WAD.
* @return 0 if committed properly, nonzero on error.
*/
int WAD_CommitEntries(wad_t *wad);
/**
* Gets a WAD entry at a particular index.
* @param wad the pointer to the open WAD.
* @param index the entry index to get.
* @return a valid pointer, or NULL if no corresponding index.
*/
wadentry_t* WAD_GetEntry(const wad_t *wad, int index);
/**
* Gets the first WAD entry by a particular name.
* Names are case-sensitive, and only the first 8 characters are compared.
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @return a valid pointer, or NULL if no corresponding entry.
*/
wadentry_t* WAD_GetEntryByName(wad_t *wad, const char *name);
/**
* Gets the first WAD entry by a particular name, from a starting index.
* Names are case-sensitive, and only the first 8 characters are compared.
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @param start the index to start from.
* @return a valid pointer, or NULL if no corresponding entry.
*/
wadentry_t* WAD_GetEntryByNameOffset(wad_t *wad, const char *name, int start);
/**
* Gets the first WAD entry by a particular name, nth instance.
* Names are case-sensitive, and only the first 8 characters are compared.
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @param nth the nth entry to retrieve (0 or 1 is the first, 2 is second, etc.).
* @return a valid pointer, or NULL if no corresponding entry.
*/
wadentry_t* WAD_GetEntryByNameNth(wad_t *wad, const char *name, int nth);
/**
* Gets the first WAD entry by a particular name, nth instance, starting from an entry index.
* Names are case-sensitive, and only the first 8 characters are compared.
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @param start the index to start from.
* @param nth the nth entry to retrieve (0 or 1 is the first, 2 is second, etc.).
* @return a valid pointer, or NULL if no corresponding entry.
*/
wadentry_t* WAD_GetEntryByNameOffsetNth(wad_t *wad, const char *name, int start, int nth);
/**
* Gets the last WAD entry by a particular name (backwards search).
* Names are case-sensitive, and only the first 8 characters are compared.
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @return a valid pointer, or NULL if no corresponding entry.
*/
wadentry_t* WAD_GetLastEntryByName(wad_t *wad, const char *name);
/**
* Counts how many entries have this name.
* Names are case-sensitive, and only the first 8 characters are compared.
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @return the amount of entries.
*/
int WAD_GetEntryCount(wad_t *wad, const char *name);
/**
* Gets the index of a particular entry.
* Names are case-sensitive, and only the first 8 characters are compared.
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @return the matching index or -1 if not found.
*/
int WAD_GetEntryIndex(wad_t *wad, const char *name);
/**
* Gets the index of a particular entry, from a starting index.
* Names are case-sensitive, and only the first 8 characters are compared.
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @param start the index to start from.
* @return the matching index or -1 if not found.
*/
int WAD_GetEntryIndexOffset(wad_t *wad, const char *name, int start);
/**
* Gets the indices of all matching lumps by name.
* Names are case-sensitive, and only the first 8 characters are compared.
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @param out the output array for the indices.
* @param max the maximum amount of indices to add.
* @return the amount of indices returned.
*/
int WAD_GetEntryIndices(wad_t *wad, const char *name, int *out, int max);
/**
* Gets the indices of all matching lumps by name.
* Names are case-sensitive, and only the first 8 characters are compared.
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @param start the index to start from.
* @param out the output array for the indices.
* @param max the maximum amount of indices to add.
* @return the amount of indices returned.
*/
int WAD_GetEntryIndicesOffset(wad_t *wad, const char *name, int start, int *out, int max);
/**
* Gets the last index of a particular entry.
* Names are case-sensitive, and only the first 8 characters are compared.
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @return the matching index or -1 if not found.
*/
int WAD_GetEntryLastIndex(wad_t *wad, const char *name);
/**
* Creates a new WAD entry at the end of the WAD.
* Bad characters in names are coerced into valid characters.
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @return a pointer to the created entry.
*/
wadentry_t* WAD_CreateEntry(wad_t *wad, const char *name);
/**
* Creates a new WAD entry at a specific index.
* The rest of the entries after the index are shifted down a position.
* Bad characters in names are coerced into valid characters.
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @param index the index position (0-based) to add the entry at.
* @return a pointer to the created entry.
*/
wadentry_t* WAD_CreateEntryAt(wad_t *wad, const char *name, int index);
/**
* Adds a new WAD entry (with content) at the end of the WAD.
* Content is appended to the end of the content blob.
* Bad characters in names are coerced into valid characters.
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @param buffer the pointer to the data to write.
* @param buffer_size the amount of data in bytes to write.
* @return a pointer to the created entry.
*/
wadentry_t* WAD_AddEntry(wad_t *wad, const char *name, unsigned char *buffer, size_t buffer_size);
/**
* Adds a new WAD entry (with content) at a specific index.
* The rest of the entries after the index are shifted down a position.
* Content is appended to the end of the content blob.
* Bad characters in names are coerced into valid characters.
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @param index the index position (0-based) to add the entry at.
* @param buffer the pointer to the data to write.
* @param buffer_size the amount of data in bytes to write.
* @return a pointer to the created entry.
*/
wadentry_t* WAD_AddEntryAt(wad_t *wad, const char *name, int index, unsigned char *buffer, size_t buffer_size);
/**
* Adds a new WAD entry (with content) at the end of the WAD, from a FILE.
* The FILE's position is not adjusted - it is read from its current position to the end.
* Content is appended to the end of the content blob.
* Bad characters in names are coerced into valid characters.
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @param stream the input stream.
* @return a pointer to the created entry.
*/
wadentry_t* WAD_AddEntryData(wad_t *wad, const char *name, FILE *stream);
/**
* Adds a new WAD entry (with content) at a specific index.
* The FILE's position is not adjusted - it is read from its current position to the end.
* The rest of the entries after the index are shifted down a position.
* Content is appended to the end of the content blob.
* Bad characters in names are coerced into valid characters.
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @param index the index position (0-based) to add the entry at.
* @param stream the input stream.
* @return a pointer to the created entry.
*/
wadentry_t* WAD_AddEntryDataAt(wad_t *wad, const char *name, int index, FILE *stream);
/**
* Adds a new WAD entry to the end of the entry list with a predefined length and offset.
* The offset provided should be set with the knowledge that the data offset in a WAD
* starts at 12 bytes in (if the content is at the 42nd byte of the content block, offset is 54).
* The offset and length provided are NOT bounds-checked! Use this function at your own risk!
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @param length the length of the entry in bytes.
* @param offset the offset into the WAD in bytes (content starts at 12).
* @return a pointer to the created entry.
*/
wadentry_t* WAD_AddExplicitEntry(wad_t *wad, const char *name, size_t length, int offset);
/**
* Adds a new WAD entry with a predefined length and offset.
* The offset provided should be set with the knowledge that the data offset in a WAD
* starts at 12 bytes in.
* The offset and length provided are NOT bounds-checked! Use this function at your own risk!
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @param index the index position (0-based) to add the entry at.
* @param length the length of the entry in bytes.
* @param offset the offset into the WAD in bytes (content starts at 12).
* @return a pointer to the created entry.
*/
wadentry_t* WAD_AddExplicitEntryAt(wad_t *wad, const char *name, int index, size_t length, int offset);
/**
* Adds a new WAD entry to the end of the entry list with a zero length.
* Equivalent to WAD_AddExplicitEntry(wad, name, 0, 0).
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @return a pointer to the created entry.
*/
wadentry_t* WAD_AddMarkerEntry(wad_t *wad, const char *name);
/**
* Adds a new WAD entry with a zero length.
* Equivalent to WAD_AddExplicitEntryAt(wad, name, index, 0, 0).
* @param wad the pointer to the open WAD.
* @param name the entry name.
* @param index the index position (0-based) to add the entry at.
* @return a pointer to the created entry.
*/
wadentry_t* WAD_AddMarkerEntryAt(wad_t *wad, const char *name, int index);
/**
* Removes an entry from the WAD (but not its content).
* The rest of the entries after the index are shifted up a position.
* @param wad the pointer to the open WAD.
* @param index the index position (0-based) to remove the entry from.
* @return 0 if successful, nonzero if not.
*/
int WAD_RemoveEntryAt(wad_t *wad, int index);
/**
* Removes an entry from the WAD (but not its content).
* The remaining entries are shifted up into their new positions to fill the gaps.
* @param wad the pointer to the open WAD.
* @param indices the array of indices to remove.
* @param count the length of the array.
* @return 0 if successful, nonzero if not.
*/
int WAD_RemoveEntriesAt(wad_t *wad, int *indices, int count);
/**
* Removes a set of entries from the WAD (but not their contents).
* The remaining entries are shifted up into their new positions to fill the gaps.
* @param wad the pointer to the open WAD.
* @param start the starting index (0-based, inclusive) to remove entries from.
* @param count the amount of entries to remove from the start.
* @return 0 if successful, nonzero if not.
*/
int WAD_RemoveEntryRange(wad_t *wad, int start, int count);
/**
* Swaps the index of an entry with an entry at another index.
* @param wad the pointer to the open WAD.
* @param a the first index (0-based, inclusive).
* @param b the second index (0-based, inclusive).
* @return 0 if successful, nonzero if not (indexes are out of bounds).
*/
int WAD_SwapEntry(wad_t *wad, int a, int b);
/**
* Moves an entry to another index.
* The entry that would be overwritten at the destination is instead displaced to after the destination.
* @param wad the pointer to the open WAD.
* @param start the starting index (0-based, inclusive) to remove entries from.
* @param destination the destination index (0-based, inclusive).
* @return 0 if successful, nonzero if not (indexes are out of bounds).
*/
int WAD_ShiftEntry(wad_t *wad, int start, int destination);
/**
* Moves a set of entries to another index.
* The entries that would be overwritten at the destination are instead displaced later in the WAD right after the moved entries.
* @param wad the pointer to the open WAD.
* @param start the starting index (0-based, inclusive) to remove entries from.
* @param count the amount of entries to move from the start.
* @param destination the destination index (0-based, inclusive).
* @return 0 if successful, nonzero if not (indexes are out of bounds).
*/
int WAD_ShiftEntries(wad_t *wad, int start, int count, int destination);
/**
* Gets the content of an entry from a WAD.
* The destination must be large enough to accomodate the data.
* This ensures a single contiguous read of the data.
* @param wad the pointer to the open WAD.
* @param entry the entry to use for length and offset.
* @param destination the destination buffer.
* @return the amount of bytes read, or -1 on a read error.
*/
int WAD_GetEntryData(wad_t *wad, wadentry_t *entry, unsigned char *destination);
/**
* Gets the content of an entry from a WAD.
* The destination must be large enough to accomodate the data.
* @param wad the pointer to the open WAD.
* @param entry the entry to use for length and offset.
* @param destination the destination buffer.
* @param size the size of a single element in bytes.
* @param count the amount of elements to read.
* @return the amount of elements read, or -1 on a read error.
*/
int WAD_ReadEntryData(wad_t *wad, wadentry_t *entry, void *destination, size_t size, size_t count);
/**
* Closes an open WAD, performs flushing operations on it if necessary,
* then frees it from memory. The pointer provided is then invalid.
* @param wad the pointer to the open WAD.
* @return 0 if closed properly and wad was freed, nonzero on error.
*/
int WAD_Close(wad_t *wad);
/**
* Creates a WAD iterator.
* NOTE: Must have WAD_IteratorNext called on it to get the first entry!
* @param wad the pointer to the open WAD.
* @param start the starting index into the entry list.
* @return the amount of entries or -1 on error.
*/
waditerator_t* WAD_IteratorCreate(wad_t *wad, int start);
/**
* Resets a WAD iterator.
* NOTE: Must have WAD_IteratorNext called on it to get the first entry!
* @param iter pointer to the iterator.
* @param start the starting index into the entry list.
* @return the amount of entries or -1 on error.
*/
void WAD_IteratorReset(waditerator_t *iter, int start);
/**
* Advances a WAD iterator to the next entry.
* @param iter pointer to the iterator.
* @return a pointer to the next entry.
*/
wadentry_t* WAD_IteratorNext(waditerator_t *iter);
/**
* Frees a WAD iterator.
* @param iter pointer to the iterator.
*/
void WAD_IteratorClose(waditerator_t *iter);
#endif

View File

@@ -0,0 +1,30 @@
/*****************************************************************************
* Copyright (c) 2018 Matt Tropiano
* All rights reserved. This source and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
*****************************************************************************/
#ifndef __WADCONFIG_H__
#define __WADCONFIG_H__
// Configuration for memory management in other systems.
#ifndef WAD_MALLOC
#define WAD_MALLOC(s) malloc((s))
#endif
#ifndef WAD_FREE
#define WAD_FREE(s) free((s))
#endif
#ifndef WAD_REALLOC
#define WAD_REALLOC(p,s) realloc((p),(s))
#endif
#ifndef WAD_CALLOC
#define WAD_CALLOC(n,s) calloc((n),(s))
#endif
#endif

View File

@@ -0,0 +1,30 @@
/*****************************************************************************
* Copyright (c) 2018 Matt Tropiano
* All rights reserved. This source and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
*****************************************************************************/
#include <stdio.h>
#include "waderrno.h"
static char *waderr[WADERROR_COUNT] = {
"No error.",
"File error.",
"Not a WAD file.",
"WAD pointer invalid.",
"Out of memory.",
"Problem closing WAD.",
"Cannot commit WAD entry list.",
"Operation not supported in this implementation.",
"Index out of range.",
};
char* strwaderror(int n)
{
if (n < 0 || n >= WADERROR_COUNT)
return NULL;
else
return waderr[n];
}

View File

@@ -0,0 +1,39 @@
/*****************************************************************************
* Copyright (c) 2018 Matt Tropiano
* All rights reserved. This source and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
*****************************************************************************/
#ifndef __WADERRNO_H__
#define __WADERRNO_H__
// This is meant to be used like <errno.h>. WAD errors and such are raised here.
// All calls into wad_* functions manipulate this value.
// Add "extern int waderrno;" to use.
#define WADERROR_NO_ERROR 0
#define WADERROR_FILE_ERROR 1
#define WADERROR_FILE_NOT_A_WAD 2
#define WADERROR_WAD_INVALID 3
#define WADERROR_OUT_OF_MEMORY 4
#define WADERROR_CANNOT_CLOSE 5
#define WADERROR_CANNOT_COMMIT 6
#define WADERROR_NOT_SUPPORTED 7
#define WADERROR_INDEX_OUT_OF_RANGE 8
#define WADERROR_COUNT 9
/**
* WAD error number.
* This field must be extern'ed to read.
*/
int waderrno;
/**
* Get the string representation of an error.
*/
char* strwaderror(int n);
#endif

View File

@@ -0,0 +1,14 @@
set(ZIP_SOURCES zip.c)
set(ZIP_HEADERS zip.h miniz.h)
if(MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -MP -W4 -WX -wd\"4127\" -wd\"4244\" -wd\"4267\" -wd\"4706\"")
else()
add_definitions(
-fsigned-char
-Wall -W
-Wstrict-prototypes -Wpointer-arith
-Wno-cast-qual -Wno-conversion)
endif()
add_library(zip STATIC ${ZIP_SOURCES} ${ZIP_HEADERS})

10130
src/cdogs/cwolfmap/zip/miniz.h Normal file

File diff suppressed because it is too large Load Diff

1793
src/cdogs/cwolfmap/zip/zip.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,464 @@
/*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#ifndef ZIP_H
#define ZIP_H
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#ifndef ZIP_SHARED
#define ZIP_EXPORT
#else
#ifdef _WIN32
#ifdef ZIP_BUILD_SHARED
#define ZIP_EXPORT __declspec(dllexport)
#else
#define ZIP_EXPORT __declspec(dllimport)
#endif
#else
#define ZIP_EXPORT __attribute__((visibility("default")))
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(_POSIX_C_SOURCE) && defined(_MSC_VER)
// 64-bit Windows is the only mainstream platform
// where sizeof(long) != sizeof(void*)
#ifdef _WIN64
typedef long long ssize_t; /* byte count or error */
#else
typedef long ssize_t; /* byte count or error */
#endif
#endif
/**
* @mainpage
*
* Documenation for @ref zip.
*/
/**
* @addtogroup zip
* @{
*/
/**
* Default zip compression level.
*/
#define ZIP_DEFAULT_COMPRESSION_LEVEL 6
/**
* Error codes
*/
#define ZIP_ENOINIT -1 // not initialized
#define ZIP_EINVENTNAME -2 // invalid entry name
#define ZIP_ENOENT -3 // entry not found
#define ZIP_EINVMODE -4 // invalid zip mode
#define ZIP_EINVLVL -5 // invalid compression level
#define ZIP_ENOSUP64 -6 // no zip 64 support
#define ZIP_EMEMSET -7 // memset error
#define ZIP_EWRTENT -8 // cannot write data to entry
#define ZIP_ETDEFLINIT -9 // cannot initialize tdefl compressor
#define ZIP_EINVIDX -10 // invalid index
#define ZIP_ENOHDR -11 // header not found
#define ZIP_ETDEFLBUF -12 // cannot flush tdefl buffer
#define ZIP_ECRTHDR -13 // cannot create entry header
#define ZIP_EWRTHDR -14 // cannot write entry header
#define ZIP_EWRTDIR -15 // cannot write to central dir
#define ZIP_EOPNFILE -16 // cannot open file
#define ZIP_EINVENTTYPE -17 // invalid entry type
#define ZIP_EMEMNOALLOC -18 // extracting data using no memory allocation
#define ZIP_ENOFILE -19 // file not found
#define ZIP_ENOPERM -20 // no permission
#define ZIP_EOOMEM -21 // out of memory
#define ZIP_EINVZIPNAME -22 // invalid zip archive name
#define ZIP_EMKDIR -23 // make dir error
#define ZIP_ESYMLINK -24 // symlink error
#define ZIP_ECLSZIP -25 // close archive error
#define ZIP_ECAPSIZE -26 // capacity size too small
#define ZIP_EFSEEK -27 // fseek error
#define ZIP_EFREAD -28 // fread error
#define ZIP_EFWRITE -29 // fwrite error
/**
* Looks up the error message string coresponding to an error number.
* @param errnum error number
* @return error message string coresponding to errnum or NULL if error is not
* found.
*/
extern ZIP_EXPORT const char *zip_strerror(int errnum);
/**
* @struct zip_t
*
* This data structure is used throughout the library to represent zip archive -
* forward declaration.
*/
struct zip_t;
/**
* Opens zip archive with compression level using the given mode.
*
* @param zipname zip archive file name.
* @param level compression level (0-9 are the standard zlib-style levels).
* @param mode file access mode.
* - 'r': opens a file for reading/extracting (the file must exists).
* - 'w': creates an empty file for writing.
* - 'a': appends to an existing archive.
*
* @return the zip archive handler or NULL on error
*/
extern ZIP_EXPORT struct zip_t *zip_open(const char *zipname, int level,
char mode);
/**
* Closes the zip archive, releases resources - always finalize.
*
* @param zip zip archive handler.
*/
extern ZIP_EXPORT void zip_close(struct zip_t *zip);
/**
* Determines if the archive has a zip64 end of central directory headers.
*
* @param zip zip archive handler.
*
* @return the return code - 1 (true), 0 (false), negative number (< 0) on
* error.
*/
extern ZIP_EXPORT int zip_is64(struct zip_t *zip);
/**
* Opens an entry by name in the zip archive.
*
* For zip archive opened in 'w' or 'a' mode the function will append
* a new entry. In readonly mode the function tries to locate the entry
* in global dictionary.
*
* @param zip zip archive handler.
* @param entryname an entry name in local dictionary.
*
* @return the return code - 0 on success, negative number (< 0) on error.
*/
extern ZIP_EXPORT int zip_entry_open(struct zip_t *zip, const char *entryname);
/**
* Opens an entry by name in the zip archive.
*
* For zip archive opened in 'w' or 'a' mode the function will append
* a new entry. In readonly mode the function tries to locate the entry
* in global dictionary (case sensitive).
*
* @param zip zip archive handler.
* @param entryname an entry name in local dictionary (case sensitive).
*
* @return the return code - 0 on success, negative number (< 0) on error.
*/
extern ZIP_EXPORT int zip_entry_opencasesensitive(struct zip_t *zip,
const char *entryname);
/**
* Opens a new entry by index in the zip archive.
*
* This function is only valid if zip archive was opened in 'r' (readonly) mode.
*
* @param zip zip archive handler.
* @param index index in local dictionary.
*
* @return the return code - 0 on success, negative number (< 0) on error.
*/
extern ZIP_EXPORT int zip_entry_openbyindex(struct zip_t *zip, size_t index);
/**
* Closes a zip entry, flushes buffer and releases resources.
*
* @param zip zip archive handler.
*
* @return the return code - 0 on success, negative number (< 0) on error.
*/
extern ZIP_EXPORT int zip_entry_close(struct zip_t *zip);
/**
* Returns a local name of the current zip entry.
*
* The main difference between user's entry name and local entry name
* is optional relative path.
* Following .ZIP File Format Specification - the path stored MUST not contain
* a drive or device letter, or a leading slash.
* All slashes MUST be forward slashes '/' as opposed to backwards slashes '\'
* for compatibility with Amiga and UNIX file systems etc.
*
* @param zip: zip archive handler.
*
* @return the pointer to the current zip entry name, or NULL on error.
*/
extern ZIP_EXPORT const char *zip_entry_name(struct zip_t *zip);
/**
* Returns an index of the current zip entry.
*
* @param zip zip archive handler.
*
* @return the index on success, negative number (< 0) on error.
*/
extern ZIP_EXPORT ssize_t zip_entry_index(struct zip_t *zip);
/**
* Determines if the current zip entry is a directory entry.
*
* @param zip zip archive handler.
*
* @return the return code - 1 (true), 0 (false), negative number (< 0) on
* error.
*/
extern ZIP_EXPORT int zip_entry_isdir(struct zip_t *zip);
/**
* Returns the uncompressed size of the current zip entry.
* Alias for zip_entry_uncomp_size (for backward compatibility).
*
* @param zip zip archive handler.
*
* @return the uncompressed size in bytes.
*/
extern ZIP_EXPORT unsigned long long zip_entry_size(struct zip_t *zip);
/**
* Returns the uncompressed size of the current zip entry.
*
* @param zip zip archive handler.
*
* @return the uncompressed size in bytes.
*/
extern ZIP_EXPORT unsigned long long zip_entry_uncomp_size(struct zip_t *zip);
/**
* Returns the compressed size of the current zip entry.
*
* @param zip zip archive handler.
*
* @return the compressed size in bytes.
*/
extern ZIP_EXPORT unsigned long long zip_entry_comp_size(struct zip_t *zip);
/**
* Returns CRC-32 checksum of the current zip entry.
*
* @param zip zip archive handler.
*
* @return the CRC-32 checksum.
*/
extern ZIP_EXPORT unsigned int zip_entry_crc32(struct zip_t *zip);
/**
* Compresses an input buffer for the current zip entry.
*
* @param zip zip archive handler.
* @param buf input buffer.
* @param bufsize input buffer size (in bytes).
*
* @return the return code - 0 on success, negative number (< 0) on error.
*/
extern ZIP_EXPORT int zip_entry_write(struct zip_t *zip, const void *buf,
size_t bufsize);
/**
* Compresses a file for the current zip entry.
*
* @param zip zip archive handler.
* @param filename input file.
*
* @return the return code - 0 on success, negative number (< 0) on error.
*/
extern ZIP_EXPORT int zip_entry_fwrite(struct zip_t *zip, const char *filename);
/**
* Extracts the current zip entry into output buffer.
*
* The function allocates sufficient memory for a output buffer.
*
* @param zip zip archive handler.
* @param buf output buffer.
* @param bufsize output buffer size (in bytes).
*
* @note remember to release memory allocated for a output buffer.
* for large entries, please take a look at zip_entry_extract function.
*
* @return the return code - the number of bytes actually read on success.
* Otherwise a negative number (< 0) on error.
*/
extern ZIP_EXPORT ssize_t zip_entry_read(struct zip_t *zip, void **buf,
size_t *bufsize);
/**
* Extracts the current zip entry into a memory buffer using no memory
* allocation.
*
* @param zip zip archive handler.
* @param buf preallocated output buffer.
* @param bufsize output buffer size (in bytes).
*
* @note ensure supplied output buffer is large enough.
* zip_entry_size function (returns uncompressed size for the current
* entry) can be handy to estimate how big buffer is needed.
* For large entries, please take a look at zip_entry_extract function.
*
* @return the return code - the number of bytes actually read on success.
* Otherwise a negative number (< 0) on error (e.g. bufsize is not large
* enough).
*/
extern ZIP_EXPORT ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf,
size_t bufsize);
/**
* Extracts the current zip entry into output file.
*
* @param zip zip archive handler.
* @param filename output file.
*
* @return the return code - 0 on success, negative number (< 0) on error.
*/
extern ZIP_EXPORT int zip_entry_fread(struct zip_t *zip, const char *filename);
/**
* Extracts the current zip entry using a callback function (on_extract).
*
* @param zip zip archive handler.
* @param on_extract callback function.
* @param arg opaque pointer (optional argument, which you can pass to the
* on_extract callback)
*
* @return the return code - 0 on success, negative number (< 0) on error.
*/
extern ZIP_EXPORT int
zip_entry_extract(struct zip_t *zip,
size_t (*on_extract)(void *arg, uint64_t offset,
const void *data, size_t size),
void *arg);
/**
* Returns the number of all entries (files and directories) in the zip archive.
*
* @param zip zip archive handler.
*
* @return the return code - the number of entries on success, negative number
* (< 0) on error.
*/
extern ZIP_EXPORT ssize_t zip_entries_total(struct zip_t *zip);
/**
* Deletes zip archive entries.
*
* @param zip zip archive handler.
* @param entries array of zip archive entries to be deleted.
* @param len the number of entries to be deleted.
* @return the number of deleted entries, or negative number (< 0) on error.
*/
extern ZIP_EXPORT ssize_t zip_entries_delete(struct zip_t *zip,
char *const entries[], size_t len);
/**
* Extracts a zip archive stream into directory.
*
* If on_extract is not NULL, the callback will be called after
* successfully extracted each zip entry.
* Returning a negative value from the callback will cause abort and return an
* error. The last argument (void *arg) is optional, which you can use to pass
* data to the on_extract callback.
*
* @param stream zip archive stream.
* @param size stream size.
* @param dir output directory.
* @param on_extract on extract callback.
* @param arg opaque pointer.
*
* @return the return code - 0 on success, negative number (< 0) on error.
*/
extern ZIP_EXPORT int
zip_stream_extract(const char *stream, size_t size, const char *dir,
int (*on_extract)(const char *filename, void *arg),
void *arg);
/**
* Opens zip archive stream into memory.
*
* @param stream zip archive stream.
* @param size stream size.
*
* @return the zip archive handler or NULL on error
*/
extern ZIP_EXPORT struct zip_t *zip_stream_open(const char *stream, size_t size,
int level, char mode);
/**
* Copy zip archive stream output buffer.
*
* @param zip zip archive handler.
* @param buf output buffer. User should free buf.
* @param bufsize output buffer size (in bytes).
*
* @return copy size
*/
extern ZIP_EXPORT ssize_t zip_stream_copy(struct zip_t *zip, void **buf,
size_t *bufsize);
/**
* Close zip archive releases resources.
*
* @param zip zip archive handler.
*
* @return
*/
extern ZIP_EXPORT void zip_stream_close(struct zip_t *zip);
/**
* Creates a new archive and puts files into a single zip archive.
*
* @param zipname zip archive file.
* @param filenames input files.
* @param len: number of input files.
*
* @return the return code - 0 on success, negative number (< 0) on error.
*/
extern ZIP_EXPORT int zip_create(const char *zipname, const char *filenames[],
size_t len);
/**
* Extracts a zip archive file into directory.
*
* If on_extract_entry is not NULL, the callback will be called after
* successfully extracted each zip entry.
* Returning a negative value from the callback will cause abort and return an
* error. The last argument (void *arg) is optional, which you can use to pass
* data to the on_extract_entry callback.
*
* @param zipname zip archive file.
* @param dir output directory.
* @param on_extract_entry on extract callback.
* @param arg opaque pointer.
*
* @return the return code - 0 on success, negative number (< 0) on error.
*/
extern ZIP_EXPORT int zip_extract(const char *zipname, const char *dir,
int (*on_extract_entry)(const char *filename,
void *arg),
void *arg);
/** @} */
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,7 +1,7 @@
/*
C-Dogs SDL
A port of the legendary (and fun) action/arcade cdogs.
Copyright (c) 2020-2023 Cong Xu
Copyright (c) 2020-2024 Cong Xu
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -96,7 +96,9 @@ static void GetCampaignPath(
}
break;
default:
CASSERT(false, "unknown map type");
// TODO: implement unknown map types
LOG(LM_MAP, LL_ERROR, "Unknown wolf map type %d", (int)type);
buf[0] = '\0';
break;
}
}
@@ -446,7 +448,7 @@ static Mix_Chunk *LoadMusic(const CWolfMap *map, const int i)
{
char *data;
size_t len;
const int err = CWAudioGetMusic(&map->audio, i, &data, &len);
const int err = CWAudioGetMusic(&map->audio, map->type, i, &data, &len);
if (err != 0)
{
goto bail;
@@ -713,6 +715,10 @@ int MapWolfLoad(
MapNewScanArchive(filename, NULL, &numMissions);
}
CFREE(c->Description);
const char *description = CWGetDescription(map, spearMission);
CSTRDUP(c->Description, description);
CharacterStoreCopy(&c->characters, &cs, &gPlayerTemplates.CustomClasses);
for (int i = 0; i < map->nLevels; i++)
@@ -806,8 +812,8 @@ static Mix_Chunk *LoadSoundData(const CWolfMap *map, const int i)
}
SDL_AudioCVT cvt;
SDL_BuildAudioCVT(
&cvt, AUDIO_U8, 1, SND_RATE, CDOGS_SND_FMT, CDOGS_SND_CHANNELS,
CDOGS_SND_RATE);
&cvt, AUDIO_U8, 1, CWGetAudioSampleRate(map), CDOGS_SND_FMT,
CDOGS_SND_CHANNELS, CDOGS_SND_RATE);
cvt.len = (int)len;
cvt.buf = (Uint8 *)SDL_malloc(cvt.len * cvt.len_mult);
memcpy(cvt.buf, data, len);

View File

@@ -38,6 +38,8 @@ void PauseMenuInit(
MenuSystemInit(&pm->ms, handlers, g, svec2i_zero(), g->cachedConfig.Res);
pm->ms.current = pm->ms.root =
MenuCreateNormal("", "", MENU_TYPE_NORMAL, 0);
// A bit counterintuitive, but QUIT means we want to quit this menu, also
// this item will get auto selected when pressing escape
MenuAddSubmenu(pm->ms.root, MenuCreate("Resume", MENU_TYPE_QUIT));
MenuAddSubmenu(pm->ms.root, MenuCreateSeparator(""));
pm->oData.config = &gConfig;