CnC_Remastered_Collection/REDALERT/INICODE.CPP

367 lines
10 KiB
C++

//
// Copyright 2020 Electronic Arts Inc.
//
// TiberianDawn.DLL and RedAlert.dll and corresponding source code 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 3 of the License, or (at your option) any later version.
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
// in the hope that it will be useful, but with permitted additional restrictions
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
// distributed with this program. You should have received a copy of the
// GNU General Public License along with permitted additional restrictions
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
/* $Header: F:\projects\c&c0\vcs\code\inicode.cpv 4.38 03 Jul 1996 05:14:04 JOE_BOSTIC $ */
/***************************************************************************
** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
***************************************************************************
* *
* Project Name : Command & Conquer *
* *
* File Name : INICODE.CPP *
* *
* Programmer : David R Dettmer *
* *
* Start Date : November 7, 1995 *
* *
* Last Update : February 20, 1996 [JLB] *
* *
*-------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#ifdef TOFIX
void Get_Scenario_Digest(char * digest, char * buffer)
{
char buf[128]; // Working string staging buffer.
char stage[sizeof(BigInt)*2];
char * stage_ptr = &stage[0];
int len = strlen(buffer) + 2;
char * tbuffer = buffer + len;
WWGetPrivateProfileString("DIGEST", NULL, NULL, tbuffer, sizeof(_staging_buffer)-len, buffer);
stage[0] = '\0';
while (*tbuffer != '\0') {
WWGetPrivateProfileString("DIGEST", tbuffer, NULL, buf, sizeof(buf)-1, buffer);
strcat(stage, buf);
tbuffer += strlen(tbuffer)+1;
}
len = strlen(stage);
char * dbuffer = &stage[0];
tbuffer = &stage[0];
for (int index = 0; index < len/2; index++) {
int c;
if (isdigit(*tbuffer)) {
c = (*tbuffer) - '0';
} else {
c = 10 + (toupper(*tbuffer) - 'A');
}
tbuffer++;
c <<= 4;
if (isdigit(*tbuffer)) {
c |= (*tbuffer) - '0';
} else {
c |= 10 + (toupper(*tbuffer) - 'A');
}
tbuffer++;
*dbuffer++ = c;
}
/*
** Decode and decrypt the number.
*/
BigInt hash = 0;
hash.DERDecode((unsigned char*)stage);
BigInt d;
d = d.Decode_ASCII(KEY_D);
BigInt n;
n = n.Decode_ASCII(KEY_N);
hash = hash.exp_b_mod_c(d, n);
memcpy(digest, &hash, 20);
buffer = strstr(buffer, "[DIGEST]");
if (buffer) {
*buffer = '\0';
}
}
bool Read_Scenario_INI_Write_INB( char *root, bool fresh)
{
char *buffer; // Scenario.ini staging buffer pointer.
char *binbuf; // Scenario.inb staging buffer pointer.
char fname[_MAX_FNAME+_MAX_EXT]; // full INI filename
char buf[256]; // Working string staging buffer.
char scenarioname[40];
int len;
unsigned char val;
/*
** Fetch working pointer to the INI staging buffer. Make sure that the buffer
** is cleared out before proceeding. (Don't use the HidPage for this, since
** the HidPage may be needed for various uncompressions during the INI
** parsing.)
*/
buffer = (char *)_staging_buffer;
memset(buffer, '\0', sizeof(_staging_buffer));
/*
** Create scenario filename and read the file.
** The previous routine verifies that the file is available.
*/
sprintf(fname,"%s.INI",root);
CCFileClass file(fname);
file.Read(buffer, sizeof(_staging_buffer)-1);
/*
** Fetch and slice off any message digest attached.
*/
char digest[20];
Get_Scenario_Digest(digest, buffer);
char real_digest[20];
SHAEngine digest_engine;
digest_engine.Hash(buffer, strlen(buffer));
digest_engine.Result(real_digest);
if (memcmp(digest, real_digest, sizeof(real_digest)) != 0) {
WWMessageBox().Process(TXT_SCENARIO_ERROR, TXT_OK);
}
/*
** Init the Scenario CRC value
*/
ScenarioCRC = 0;
len = strlen(buffer);
for (int i = 0; i < len; i++) {
val = (unsigned char)buffer[i];
Add_CRC(&ScenarioCRC, (unsigned long)val);
}
sprintf(fname,"%s.INB",root);
file.Set_Name(fname);
file.Cache(16384);
file.Open(WRITE);
unsigned long crc = Ini_Binary_Version();
file.Write( (char *)&crc, sizeof(crc) );
binbuf = (char *)Alloc( sizeof(_staging_buffer), MEM_NORMAL );
if (binbuf) {
Write_Bin_Init( binbuf, sizeof(_staging_buffer) );
} else {
Print_Error_End_Exit( "Unable to alloc space for writing INB" );
}
/*
** Fetch the appropriate movie names from the INI file.
*/
WWGetPrivateProfileString("Basic", "Name", "", scenarioname, sizeof(scenarioname), buffer);
WWGetPrivateProfileString("Basic", "Intro", "x", Scen.IntroMovie, sizeof(Scen.IntroMovie), buffer);
WWGetPrivateProfileString("Basic", "Brief", "x", Scen.BriefMovie, sizeof(Scen.BriefMovie), buffer);
WWGetPrivateProfileString("Basic", "Win", "x", Scen.WinMovie, sizeof(Scen.WinMovie), buffer);
WWGetPrivateProfileString("Basic", "Lose", "x", Scen.LoseMovie, sizeof(Scen.LoseMovie), buffer);
WWGetPrivateProfileString("Basic", "Action", "x", Scen.ActionMovie, sizeof(Scen.ActionMovie), buffer);
Scen.IsToCarryOver = WWGetPrivateProfileInt("Basic", "ToCarryOver", 0, buffer);
Scen.IsToInherit = WWGetPrivateProfileInt("Basic", "ToInherit", 0, buffer);
Write_Bin_String( scenarioname, strlen(scenarioname), binbuf );
Write_Bin_String( Scen.IntroMovie, strlen(Scen.IntroMovie), binbuf );
Write_Bin_String( Scen.BriefMovie, strlen(Scen.BriefMovie), binbuf );
Write_Bin_String( Scen.WinMovie, strlen(Scen.WinMovie), binbuf );
Write_Bin_String( Scen.LoseMovie, strlen(Scen.LoseMovie), binbuf );
Write_Bin_String( Scen.ActionMovie, strlen(Scen.ActionMovie), binbuf );
/*
** Fetch the transition theme for this scenario.
*/
Scen.TransitTheme = THEME_NONE;
WWGetPrivateProfileString("Basic", "Theme", "No Theme", buf, sizeof(buf), buffer);
Scen.TransitTheme = Theme.From_Name(buf);
WWGetPrivateProfileString( "Basic", "Player", "Greece", buf, 127, buffer);
Scen.PlayerHouse = HouseTypeClass::From_Name(buf);
if (Scen.PlayerHouse >= HOUSE_MULTI1) {
Scen.PlayerHouse = HOUSE_GREECE;
}
// TCTC To Fix?
// Scen.CarryOverPercent = WWGetPrivateProfileInt( "Basic", "CarryOverMoney", 100, buffer);
Scen.CarryOverCap = WWGetPrivateProfileInt( "Basic", "CarryOverCap", -1, buffer);
Scen.Percent = WWGetPrivateProfileInt( "Basic", "Percent", 0, buffer);
Write_Bin_Num( &Scen.TransitTheme, sizeof(Scen.TransitTheme), binbuf );
Write_Bin_Num( &Scen.PlayerHouse, sizeof(Scen.PlayerHouse), binbuf );
Write_Bin_Num( &Scen.CarryOverPercent, 1, binbuf );
Write_Bin_Num( &Scen.CarryOverCap, 2, binbuf );
Write_Bin_Num( &Scen.Percent, 1, binbuf );
/*
** Read in the specific information for each of the house types. This creates
** the houses of different types.
*/
HouseClass::Read_INI(buffer);
Call_Back();
/*
** Read in the team-type data. The team types must be created before any
** triggers can be created.
*/
TeamTypeClass::Read_INI(buffer);
Call_Back();
/*
** Assign PlayerPtr by reading the player's house from the INI;
** Must be done before any TechnoClass objects are created.
*/
if (Session.Type == GAME_NORMAL) {
Scen.CarryOverPercent = Cardinal_To_Fixed(100, Scen.CarryOverPercent);
PlayerPtr = HouseClass::As_Pointer( Scen.PlayerHouse );
assert(PlayerPtr != NULL);
PlayerPtr->IsHuman = true;
int carryover;
if (Scen.CarryOverCap != -1) {
carryover = MIN(Fixed_To_Cardinal(Scen.CarryOverMoney, Scen.CarryOverPercent), (Scen.CarryOverCap * 100) );
} else {
carryover = Fixed_To_Cardinal(Scen.CarryOverMoney, Scen.CarryOverPercent);
}
PlayerPtr->Credits += carryover;
PlayerPtr->Control.InitialCredits += carryover;
} else {
Assign_Houses();
}
/*
** Read in the trigger data. The triggers must be created before any other
** objects can be initialized.
*/
TriggerClass::Read_INI(buffer);
Call_Back();
/*
** Read in the map control values. This includes dimensions
** as well as theater information.
*/
Map.Read_INI(buffer);
Call_Back();
/*
** Attempt to read the map's binary image file; if fails, read the
** template data from the INI, for backward compatibility
*/
if (fresh) {
if (!Map.Read_Binary(root, &ScenarioCRC)) {
return( false );
}
}
Call_Back();
/*
** Read in and place the 3D terrain objects.
*/
TerrainClass::Read_INI(buffer);
Call_Back();
/*
** Read in and place the units (all sides).
*/
UnitClass::Read_INI(buffer);
Call_Back();
AircraftClass::Read_INI(buffer);
Call_Back();
VesselClass::Read_INI(buffer);
Call_Back();
/*
** Read in and place the infantry units (all sides).
*/
InfantryClass::Read_INI(buffer);
Call_Back();
/*
** Read in and place all the buildings on the map.
*/
BuildingClass::Read_INI(buffer);
Call_Back();
/*
** Read in the AI's base information.
*/
Base.Read_INI(buffer);
Call_Back();
/*
** Read in any normal overlay objects.
*/
OverlayClass::Read_INI(buffer);
Call_Back();
/*
** Read in any smudge overlays.
*/
SmudgeClass::Read_INI(buffer);
Call_Back();
/*
** Read in any briefing text.
*/
char * stage = &Scen.BriefingText[0];
*stage = '\0';
int index = 1;
/*
** Build the full text of the mission objective.
*/
for (;;) {
char buff[16];
sprintf(buff, "%d", index++);
*stage = '\0';
WWGetPrivateProfileString("Briefing", buff, "", stage, 255, buffer);
if (strlen(stage) == 0) break;
strcat(stage, " ");
stage += strlen(stage);
}
len = Write_Bin_Length( binbuf );
if (len != -1) {
file.Write( binbuf, len );
}
Free( binbuf );
file.Close();
return(true);
}
#endif