Split scenarios into .inc files

This commit is contained in:
Ryan Dwyer 2022-01-09 00:14:43 +10:00
parent df3c389b1c
commit 4167ec8c89
25 changed files with 2897 additions and 2845 deletions

View File

@ -1037,7 +1037,7 @@ u32 botPickupProp(struct prop *prop, struct chrdata *chr)
if (weapon->weaponnum == WEAPON_BRIEFCASE2) {
result = scenarioPickUpBriefcase(chr, prop);
} else if (weapon->weaponnum == WEAPON_DATAUPLINK) {
result = chrGiveUplink(chr, prop);
result = scenarioPickUpUplink(chr, prop);
} else {
propPlayPickupSound(prop, weapon->weaponnum);
qty = weaponGetPickupAmmoQty(weapon);
@ -1361,7 +1361,7 @@ glabel var7f1b3480nb
.NB0f18ab4c:
/* f18ab4c: 14a10005 */ bne $a1,$at,.NB0f18ab64
/* f18ab50: 02402025 */ or $a0,$s2,$zero
/* f18ab54: 0fc60612 */ jal chrGiveUplink
/* f18ab54: 0fc60612 */ jal scenarioPickUpUplink
/* f18ab58: 8fa50080 */ lw $a1,0x80($sp)
/* f18ab5c: 1000005b */ beqz $zero,.NB0f18accc
/* f18ab60: 8fbf0054 */ lw $ra,0x54($sp)
@ -3191,7 +3191,7 @@ glabel var7f1b8ef0
/* f191f54: 8fbf0024 */ lw $ra,0x24($sp)
/* f191f58: 51c00004 */ beqzl $t6,.L0f191f6c
/* f191f5c: 8faf0058 */ lw $t7,0x58($sp)
/* f191f60: 0fc615c8 */ jal scenarioCallback14
/* f191f60: 0fc615c8 */ jal scenarioTickChr
/* f191f64: 02202025 */ or $a0,$s1,$zero
/* f191f68: 8faf0058 */ lw $t7,0x58($sp)
.L0f191f6c:
@ -3703,7 +3703,7 @@ glabel var7f1b8ef0
/* f191f54: 8fbf0024 */ lw $ra,0x24($sp)
/* f191f58: 51c00004 */ beqzl $t6,.L0f191f6c
/* f191f5c: 8faf0058 */ lw $t7,0x58($sp)
/* f191f60: 0fc615c8 */ jal scenarioCallback14
/* f191f60: 0fc615c8 */ jal scenarioTickChr
/* f191f64: 02202025 */ or $a0,$s1,$zero
/* f191f68: 8faf0058 */ lw $t7,0x58($sp)
.L0f191f6c:
@ -3902,7 +3902,7 @@ glabel var7f1b8ef0
//
// if (g_Vars.lvframe60 >= 145) {
// if (updateable) {
// scenarioCallback14(chr);
// scenarioTickChr(chr);
// }
//
// if (updateable && !chrIsDead(chr)) {
@ -7335,11 +7335,7 @@ s32 botGetNumOpponentsInHill(struct chrdata *chr)
if (g_MpAllChrPtrs[i]->prop->rooms[0] == g_ScenarioData.koh.hillrooms[0]) {
s32 mpindex = func0f18d074(i);
if (mpindex < 4) {
loopmpchr = &g_PlayerConfigsArray[mpindex].base;
} else {
loopmpchr = &g_BotConfigsArray[mpindex - 4].base;
}
loopmpchr = MPCHR(mpindex);
if (loopmpchr->team != mpchr->team) {
countsperteam[loopmpchr->team]++;

View File

@ -1143,7 +1143,7 @@ void botinvDrop(struct chrdata *chr, s32 weaponnum, u8 dropall)
objDrop(prop, true);
if (item->type_weap.weapon1 == WEAPON_BRIEFCASE2) {
scenarioReleaseToken(chr, prop);
scenarioHandleDroppedToken(chr, prop);
}
}
}

View File

@ -8347,7 +8347,7 @@ Gfx *chrRender(struct prop *prop, Gfx *gdl, bool withalpha)
}
if (g_Vars.normmplayerisrunning) {
speb = scenarioHighlight(prop, colour);
speb = scenarioHighlightProp(prop, colour);
}
if (!speb) {

View File

@ -3641,7 +3641,7 @@ glabel var7f1a7dd4
/* f004104: 27a50080 */ addiu $a1,$sp,0x80
/* f004108: 27a6007c */ addiu $a2,$sp,0x7c
/* f00410c: 27a70078 */ addiu $a3,$sp,0x78
/* f004110: 0fc6192e */ jal scenarioCallback38
/* f004110: 0fc6192e */ jal scenarioHighlightRoom
/* f004114: afa20080 */ sw $v0,0x80($sp)
/* f004118: 8fb80080 */ lw $t8,0x80($sp)
/* f00411c: 8e790000 */ lw $t9,0x0($s3)
@ -4471,7 +4471,7 @@ glabel var7f1a7dd4
/* f003e4c: 27a50080 */ addiu $a1,$sp,0x80
/* f003e50: 27a6007c */ addiu $a2,$sp,0x7c
/* f003e54: 27a70078 */ addiu $a3,$sp,0x78
/* f003e58: 0fc60248 */ jal scenarioCallback38
/* f003e58: 0fc60248 */ jal scenarioHighlightRoom
/* f003e5c: afa20080 */ sw $v0,0x80($sp)
/* f003e60: 8fb90080 */ lw $t9,0x80($sp)
/* f003e64: 8e680000 */ lw $t0,0x0($s3)
@ -5085,7 +5085,7 @@ glabel var7f1a7ddc
/* f004b7c: 27a70078 */ addiu $a3,$sp,0x78
/* f004b80: afa9003c */ sw $t1,0x3c($sp)
/* f004b84: afaa0040 */ sw $t2,0x40($sp)
/* f004b88: 0fc6192e */ jal scenarioCallback38
/* f004b88: 0fc6192e */ jal scenarioHighlightRoom
/* f004b8c: afac0074 */ sw $t4,0x74($sp)
/* f004b90: 3c1f8007 */ lui $ra,%hi(g_InCutscene)
/* f004b94: 27ff0764 */ addiu $ra,$ra,%lo(g_InCutscene)

View File

@ -2838,7 +2838,7 @@ void setupLoadFiles(s32 stagenum)
total += setupCountCommandType(OBJTYPE_ESCASTEP);
if (g_Vars.normmplayerisrunning) {
total += scenarioCallback08();
total += scenarioNumProps();
}
func0f011130(total, numchrs);
@ -3480,7 +3480,7 @@ void setupParseObjects(s32 stagenum)
}
if (g_Vars.normmplayerisrunning) {
scenarioReset();
scenarioInitProps();
}
obj = (struct defaultobj *)g_StageSetup.props;

View File

@ -11,6 +11,7 @@
#include "game/training/training.h"
#include "game/lang.h"
#include "game/mplayer/mplayer.h"
#include "game/mplayer/scenarios.h"
#include "game/pad.h"
#include "bss.h"
#include "lib/dma.h"

View File

@ -429,7 +429,7 @@ void lvInit(s32 stagenum)
func0f011110();
func0f0108d0();
setupLoadFiles(stagenum);
mpPrepareScenario();
scenarioReset();
gvarsInitProps();
setupInit();
func0f00b510();
@ -815,7 +815,7 @@ glabel var7f1b1f44nc
/* f162a94: 00000000 */ sll $zero,$zero,0x0
/* f162a98: 0fc03a25 */ jal setupLoadFiles
/* f162a9c: 8fa40020 */ lw $a0,0x20($sp)
/* f162aa0: 0fc6019d */ jal mpPrepareScenario
/* f162aa0: 0fc6019d */ jal scenarioReset
/* f162aa4: 00000000 */ sll $zero,$zero,0x0
/* f162aa8: 0fc02fbc */ jal gvarsInitProps
/* f162aac: 00000000 */ sll $zero,$zero,0x0
@ -2242,7 +2242,7 @@ glabel var7f1b8e7cpf
/* f16ad40: 00000000 */ nop
/* f16ad44: 0fc18ca3 */ jal propsTick
/* f16ad48: 02202025 */ move $a0,$s1
/* f16ad4c: 0fc619c9 */ jal scenarioCallback14
/* f16ad4c: 0fc619c9 */ jal scenarioTickChr
/* f16ad50: 00002025 */ move $a0,$zero
/* f16ad54: 0fc18104 */ jal propsSort
/* f16ad58: 00000000 */ nop
@ -3655,7 +3655,7 @@ Gfx *lvRender(Gfx *gdl)
roomsTick();
func0f004314();
propsTick(islastplayer);
scenarioCallback14(NULL);
scenarioTickChr(NULL);
propsSort();
autoaimTick();
handsTickAttack();
@ -4830,7 +4830,7 @@ glabel var7f1b1fd4nb
/* f164a48: 00000000 */ sll $zero,$zero,0x0
/* f164a4c: 0fc188ac */ jal propsTick
/* f164a50: 02202025 */ or $a0,$s1,$zero
/* f164a54: 0fc5ff30 */ jal scenarioCallback14
/* f164a54: 0fc5ff30 */ jal scenarioTickChr
/* f164a58: 00002025 */ or $a0,$zero,$zero
/* f164a5c: 0fc17d1c */ jal propsSort
/* f164a60: 00000000 */ sll $zero,$zero,0x0

View File

@ -10879,11 +10879,7 @@ Gfx *menuRenderItemPlayerStats(Gfx *gdl, struct menurendercontext *context)
s32 gap;
s32 ypos = 0;
if (playernum < 4) {
mpchr = &g_PlayerConfigsArray[playernum].base;
} else {
mpchr = &g_BotConfigsArray[playernum - 4].base;
}
mpchr = MPCHR(playernum);
gdl = func0f153628(gdl);
@ -11035,13 +11031,7 @@ Gfx *menuRenderItemPlayerStats(Gfx *gdl, struct menurendercontext *context)
for (i = 0; i < 12; i++) {
if (g_MpSetup.chrslots & (1 << i)) {
struct mpchrconfig *loopmpchr;
if (i < 4) {
loopmpchr = &g_PlayerConfigsArray[i].base;
} else {
loopmpchr = &g_BotConfigsArray[i - 4].base;
}
struct mpchrconfig *loopmpchr = MPCHR(i);
if (i != playernum) {
// Name

View File

@ -30,7 +30,7 @@ struct menudialog g_MpEndscreenSavePlayerMenuDialog;
s32 mpStatsForPlayerDropdownHandler(s32 operation, struct menuitem *item, union handlerdata *data)
{
char *name;
struct mpchrconfig *mpchr;
s32 v0;
s32 v1;
s32 a1;
@ -50,14 +50,10 @@ s32 mpStatsForPlayerDropdownHandler(s32 operation, struct menuitem *item, union
for (a1 = 0; a1 < 12; a1++) {
if (g_MpSetup.chrslots & (1 << a1)) {
if (a1 < 4) {
name = g_PlayerConfigsArray[a1].base.name;
} else {
name = g_BotConfigsArray[a1 - 4].base.name;
}
mpchr = MPCHR(a1);
if (v0 == data->list.value) {
return (s32) name;
return (s32) mpchr->name;
}
v0++;
@ -216,16 +212,10 @@ char *mpMenuTextWeaponDescription(struct menuitem *item)
char *mpMenuTitleStatsFor(struct menudialog *dialog)
{
char *name;
if (g_MpSelectedPlayersForStats[g_MpPlayerNum] < 4) {
name = g_PlayerConfigsArray[g_MpSelectedPlayersForStats[g_MpPlayerNum]].base.name;
} else {
name = g_BotConfigsArray[g_MpSelectedPlayersForStats[g_MpPlayerNum] - 4].base.name;
}
struct mpchrconfig *mpchr = MPCHR(g_MpSelectedPlayersForStats[g_MpPlayerNum]);
// "Stats for %s"
sprintf(g_StringPointer, langGet(L_MPMENU_280), name);
sprintf(g_StringPointer, langGet(L_MPMENU_280), mpchr->name);
return g_StringPointer;
}

View File

@ -246,13 +246,7 @@ void mpInit(void)
}
for (i = 0; i != 12; i++) {
struct mpchrconfig *mpchr;
if (i < 4) {
mpchr = &g_PlayerConfigsArray[i].base;
} else {
mpchr = &g_BotConfigsArray[i - 4].base;
}
struct mpchrconfig *mpchr = MPCHR(i);
func0f187838(mpchr);
@ -1121,11 +1115,7 @@ s32 mpCalculateTeamScore(s32 teamnum, s32 *result)
for (i = 0; i < 12; i++) {
if (g_MpSetup.chrslots & (1 << i)) {
if (i < 4) {
mpchr = &g_PlayerConfigsArray[i].base;
} else {
mpchr = &g_BotConfigsArray[i - 4].base;
}
mpchr = MPCHR(i);
if (mpchr->team == teamnum) {
scenarioCalculatePlayerScore(mpchr, i, &score, &deaths);
@ -7217,11 +7207,7 @@ void mpFindUnusedHeadAndBody(u8 *mpheadnum, u8 *mpbodynum)
for (i = 0; i < 12; i++) {
if (g_MpSetup.chrslots & (1 << i)) {
if (i < 4) {
mpchr = &g_PlayerConfigsArray[i].base;
} else {
mpchr = &g_BotConfigsArray[i - 4].base;
}
mpchr = MPCHR(i);
if (mpchr->mpheadnum == trympheadnum) {
available = false;
@ -7940,11 +7926,7 @@ struct mpchrconfig *mpGetChrConfigBySlotNum(s32 slot)
for (i = 0; i < 12; i++) {
if (g_MpSetup.chrslots & (1 << i)) {
if (count == slot) {
if (i < 4) {
result = &g_PlayerConfigsArray[i].base;
} else {
result = &g_BotConfigsArray[i - 4].base;
}
result = MPCHR(i);
break;
}
@ -8002,13 +7984,7 @@ u8 mpFindUnusedTeamNum(void)
for (i = 0; i < 12; i++) {
if (g_MpSetup.chrslots & (1 << i)) {
struct mpchrconfig *mpchr;
if (i < 4) {
mpchr = &g_PlayerConfigsArray[i].base;
} else {
mpchr = &g_BotConfigsArray[i - 4].base;
}
struct mpchrconfig *mpchr = MPCHR(i);
if (mpchr->team == teamnum) {
available = false;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,437 @@
/**
* Capture the Case
*
* Each team has a base. The base is highlighted in their team colour and
* contains a briefcase on the ground. Players must infiltrate another team's
* base, collect their briefcase and then return it to their own.
*
* When a briefcase holder is killed, the briefcase is immediately returned to
* the team's base.
*
* Players cannot score unless their briefcase is at the home base.
*/
struct menuitem g_CtcOptionsMenuItems[] = {
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_222, MPOPTION_ONEHITKILLS, menuhandlerMpOneHitKills }, // "One-Hit Kills"
{ MENUITEMTYPE_DROPDOWN, 0, 0x00020000, L_MPMENU_223, 0x00000000, menuhandlerMpSlowMotion }, // "Slow Motion"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_224, MPOPTION_FASTMOVEMENT, menuhandlerMpCheckboxOption }, // "Fast Movement"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_225, MPOPTION_DISPLAYTEAM, menuhandlerMpDisplayTeam }, // "Display Team"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_226, MPOPTION_NORADAR, menuhandlerMpCheckboxOption }, // "No Radar"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_227, MPOPTION_NOAUTOAIM, menuhandlerMpCheckboxOption }, // "No Auto-Aim"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_OPTIONS_493, MPOPTION_KILLSSCORE, menuhandlerMpCheckboxOption }, // "Kills Score"
{ MENUITEMTYPE_SEPARATOR, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_236, MPOPTION_CTC_SHOWONRADAR, menuhandlerMpCheckboxOption }, // "Show on Radar"
{ MENUITEMTYPE_SEPARATOR, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
{ MENUITEMTYPE_SELECTABLE, 0, 0x00000008, L_MPMENU_239, 0x00000000, NULL }, // "Back"
{ MENUITEMTYPE_END, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
};
struct menudialog g_CtcOptionsMenuDialog = {
MENUDIALOGTYPE_DEFAULT,
L_MPMENU_220, // "Capture Options"
g_CtcOptionsMenuItems,
mpOptionsMenuDialog,
0x00000010,
NULL,
};
struct weaponobj g_CtcTokenObj0;
struct weaponobj g_CtcTokenObj1;
struct weaponobj g_CtcTokenObj2;
struct weaponobj g_CtcTokenObj3;
void ctcInit(void)
{
s32 i, j, k;
g_MpSetup.options |= MPOPTION_TEAMSENABLED;
for (i = 0; i < 4; i++) {
s32 j;
g_ScenarioData.ctc.spawnpadsperteam[i].homepad = i;
g_ScenarioData.ctc.spawnpadsperteam[i].numspawnpads = 0;
for (j = 0; j < 6; j++) {
g_ScenarioData.ctc.spawnpadsperteam[i].spawnpads[j] = -1;
}
}
for (i = 0; i != 4; i++) {
g_ScenarioData.ctc.playercountsperteam[i] = 0;
g_ScenarioData.ctc.teamindexes[i] = -1;
}
for (k = 0; k < MAX_MPCHRS; k++) {
if (g_MpSetup.chrslots & (1 << k)) {
struct mpchrconfig *mpchr = MPCHR(k);
while (mpchr->team >= scenarioGetMaxTeams()) {
mpchr->team -= scenarioGetMaxTeams();
}
}
}
}
s32 ctcNumProps(void)
{
return 4;
}
void ctcTick(void)
{
// empty
}
void ctcTickChr(struct chrdata *chr)
{
if (chr);
}
void ctcInitProps(void)
{
struct mpchrconfig *mpchr;
struct weaponobj *tmp;
s32 mpindex;
u32 stack;
bool teamsdone[4];
struct weaponobj template = {
256, // extrascale
0, // hidden2
OBJTYPE_WEAPON, // type
MODEL_CHRBRIEFCASE, // modelnum
0, // pad
OBJFLAG_00000001 | OBJFLAG_INVINCIBLE | OBJFLAG_00400000,
OBJFLAG2_IMMUNETOGUNFIRE | OBJFLAG2_00200000,
0, // flags3
NULL, // prop
NULL, // model
1, 0, 0, // realrot
0, 1, 0,
0, 0, 1,
0, // hidden
NULL, // geo
NULL, // projectile
0, // damage
1000, // maxdamage
0xff, 0xff, 0xff, 0x00, // shadecol
0xff, 0xff, 0xff, 0x00, // nextcol
0x0fff, // floorcol
0, // tiles
WEAPON_BRIEFCASE2, // weaponnum
0, // unk5d
0, // unk5e
FUNC_PRIMARY, // gunfunc
0, // fadeouttimer60
-1, // dualweaponnum
-1, // timer240
NULL, // dualweapon
};
s32 i;
s32 j;
s32 k;
for (i = 0; i < 4; i++) {
for (j = 0; j < 6; j++) {
}
}
for (i = 0; i < 4; i++) {
teamsdone[i] = false;
g_ScenarioData.ctc.playercountsperteam[i] = 0;
}
for (i = 0; i != 4; i++) {
do {
g_ScenarioData.ctc.teamindexes[i] = random() % 4;
} while (teamsdone[g_ScenarioData.ctc.teamindexes[i]]);
teamsdone[g_ScenarioData.ctc.teamindexes[i]] = true;
}
for (k = 0; k < 12; k++) {
if (g_MpSetup.chrslots & (1 << k)) {
mpchr = MPCHR(k);
while (mpchr->team >= scenarioGetMaxTeams()) {
mpchr->team -= scenarioGetMaxTeams();
}
#if VERSION >= VERSION_NTSC_1_0
mpindex = func0f18d0e8(k);
if (mpindex >= 0) {
struct chrdata *chr = mpGetChrFromPlayerIndex(mpindex);
if (chr) {
chr->team = 1 << mpchr->team;
}
}
#else
if (func0f18d0e8(k) >= 0) {
struct chrdata *chr = mpGetChrFromPlayerIndex(func0f18d0e8(k));
if (chr) {
chr->team = 1 << mpchr->team;
}
}
#endif
g_ScenarioData.ctc.playercountsperteam[mpchr->team]++;
}
}
for (i = 0; i < 4; i++) {
if (g_ScenarioData.ctc.playercountsperteam[i] == 0) {
g_ScenarioData.ctc.teamindexes[i] = -1;
}
}
for (i = 0; i < 4; i++) {
// empty
}
for (i = 0; i < 4; i++) {
g_ScenarioData.ctc.tokens[i] = NULL;
}
for (i = 0; i < 4; i++) {
g_ScenarioData.ctc.baserooms[i] = -1;
}
if (g_ScenarioData.ctc.playercountsperteam[0] != 0) {
g_CtcTokenObj0 = template;
tmp = &g_CtcTokenObj0;
tmp->base.pad = g_ScenarioData.ctc.spawnpadsperteam[g_ScenarioData.ctc.teamindexes[0]].homepad;
weaponAssignToHome(tmp, 1000);
g_ScenarioData.ctc.tokens[0] = tmp->base.prop;
tmp->base.hidden2 &= ~OBJH2FLAG_CANREGEN;
tmp->team = 0;
g_ScenarioData.ctc.baserooms[0] = g_ScenarioData.ctc.tokens[0]->rooms[0];
}
if (g_ScenarioData.ctc.playercountsperteam[1] != 0) {
g_CtcTokenObj1 = template;
tmp = &g_CtcTokenObj1;
tmp->base.pad = g_ScenarioData.ctc.spawnpadsperteam[g_ScenarioData.ctc.teamindexes[1]].homepad;
weaponAssignToHome(tmp, 1001);
g_ScenarioData.ctc.tokens[1] = tmp->base.prop;
tmp->base.hidden2 &= ~OBJH2FLAG_CANREGEN;
tmp->team = 1;
g_ScenarioData.ctc.baserooms[1] = g_ScenarioData.ctc.tokens[1]->rooms[0];
}
if (g_ScenarioData.ctc.playercountsperteam[2] != 0) {
g_CtcTokenObj2 = template;
tmp = &g_CtcTokenObj2;
tmp->base.pad = g_ScenarioData.ctc.spawnpadsperteam[g_ScenarioData.ctc.teamindexes[2]].homepad;
weaponAssignToHome(tmp, 1002);
g_ScenarioData.ctc.tokens[2] = tmp->base.prop;
tmp->base.hidden2 &= ~OBJH2FLAG_CANREGEN;
tmp->team = 2;
g_ScenarioData.ctc.baserooms[2] = g_ScenarioData.ctc.tokens[2]->rooms[0];
}
if (g_ScenarioData.ctc.playercountsperteam[3] != 0) {
g_CtcTokenObj3 = template;
tmp = &g_CtcTokenObj3;
tmp->base.pad = g_ScenarioData.ctc.spawnpadsperteam[g_ScenarioData.ctc.teamindexes[3]].homepad;
weaponAssignToHome(tmp, 1003);
g_ScenarioData.ctc.tokens[3] = tmp->base.prop;
tmp->base.hidden2 &= ~OBJH2FLAG_CANREGEN;
tmp->team = 3;
g_ScenarioData.ctc.baserooms[3] = g_ScenarioData.ctc.tokens[3]->rooms[0];
}
for (i = 0; i < 4; i++) {
if (g_ScenarioData.ctc.playercountsperteam[i] && g_ScenarioData.ctc.baserooms[i] != -1) {
roomSetLighting(g_ScenarioData.ctc.baserooms[i], 5, 0, 0, 0);
}
}
}
void ctcCalculatePlayerScore(struct mpchrconfig *mpchr, s32 mpchrnum, s32 *score, s32 *deaths)
{
struct mpchrconfig *loopmpchr;
s32 i;
*score = 0;
*score += mpchr->numpoints * 3;
if (g_MpSetup.options & MPOPTION_KILLSSCORE) {
for (i = 0; i != MAX_MPCHRS; i++) {
if (i == mpchrnum) {
*score -= mpchr->killcounts[i];
} else {
loopmpchr = MPCHR(i);
if (loopmpchr->team == mpchr->team) {
*score -= mpchr->killcounts[i];
} else {
*score += mpchr->killcounts[i];
}
}
}
}
*deaths = mpchr->numdeaths;
}
Gfx *ctcRadarExtra(Gfx *gdl)
{
if (g_MpSetup.options & MPOPTION_CTC_SHOWONRADAR) {
s32 i;
for (i = 0; i < scenarioGetMaxTeams(); i++) {
if (g_ScenarioData.ctc.tokens[i] &&
g_ScenarioData.ctc.tokens[i]->type != PROPTYPE_CHR &&
g_ScenarioData.ctc.tokens[i]->type != PROPTYPE_PLAYER) {
struct coord dist;
dist.x = g_ScenarioData.ctc.tokens[i]->pos.x - g_Vars.currentplayer->prop->pos.x;
dist.y = g_ScenarioData.ctc.tokens[i]->pos.y - g_Vars.currentplayer->prop->pos.y;
dist.z = g_ScenarioData.ctc.tokens[i]->pos.z - g_Vars.currentplayer->prop->pos.z;
gdl = radarDrawDot(gdl, g_ScenarioData.ctc.tokens[i], &dist, g_TeamColours[i], 0, 1);
}
}
}
return gdl;
}
bool ctcRadarChr(Gfx **gdl, struct prop *prop)
{
s32 i;
if (g_MpSetup.options & MPOPTION_CTC_SHOWONRADAR) {
for (i = 0; i < scenarioGetMaxTeams(); i++) {
if (prop == g_ScenarioData.ctc.tokens[i] &&
(g_ScenarioData.ctc.tokens[i]->type == PROPTYPE_CHR || g_ScenarioData.ctc.tokens[i]->type == PROPTYPE_PLAYER)) {
struct coord dist;
s32 colour = g_TeamColours[radarGetTeamIndex(prop->chr->team)];
dist.x = g_ScenarioData.ctc.tokens[i]->pos.x - g_Vars.currentplayer->prop->pos.x;
dist.y = g_ScenarioData.ctc.tokens[i]->pos.y - g_Vars.currentplayer->prop->pos.y;
dist.z = g_ScenarioData.ctc.tokens[i]->pos.z - g_Vars.currentplayer->prop->pos.z;
*gdl = radarDrawDot(*gdl, g_ScenarioData.ctc.tokens[i], &dist,
g_TeamColours[i], colour, 1);
return true;
}
}
}
return false;
}
bool ctcHighlightProp(struct prop *prop, s32 *colour)
{
struct defaultobj *obj = prop->obj;
if (prop->type == PROPTYPE_OBJ || prop->type == PROPTYPE_WEAPON || prop->type == PROPTYPE_DOOR) {
if (obj->type == OBJTYPE_WEAPON) {
struct weaponobj *weapon = prop->weapon;
if (weapon->weaponnum == WEAPON_BRIEFCASE2) {
u32 teamcolour = g_TeamColours[weapon->team];
colour[0] = teamcolour >> 24 & 0xff;
colour[1] = teamcolour >> 16 & 0xff;
colour[2] = teamcolour >> 8 & 0xff;
colour[3] = 75;
return true;
}
}
}
return false;
}
void ctcAddPad(s32 *cmd)
{
s32 i;
if (cmd[0] == INTROCMD_CASE) {
g_ScenarioData.ctc.spawnpadsperteam[cmd[1]].homepad = cmd[2];
}
if (cmd[0] == INTROCMD_CASERESPAWN) {
for (i = 0; i != ARRAYCOUNT(g_ScenarioData.ctc.spawnpadsperteam[cmd[1]].spawnpads); i++) {
if (g_ScenarioData.ctc.spawnpadsperteam[cmd[1]].spawnpads[i] == -1) {
g_ScenarioData.ctc.spawnpadsperteam[cmd[1]].spawnpads[i] = cmd[2];
g_ScenarioData.ctc.spawnpadsperteam[cmd[1]].numspawnpads++;
return;
}
}
}
}
bool ctcChooseSpawnLocation(f32 arg0, struct coord *pos, s16 *rooms, struct prop *prop, f32 *arg4)
{
struct chrdata *chr = prop->chr;
s32 index = radarGetTeamIndex(chr->team);
if (g_ScenarioData.ctc.spawnpadsperteam[g_ScenarioData.ctc.teamindexes[index]].numspawnpads > 0) {
*arg4 = playerChooseSpawnLocation(arg0, pos, rooms, prop,
g_ScenarioData.ctc.spawnpadsperteam[g_ScenarioData.ctc.teamindexes[index]].spawnpads,
g_ScenarioData.ctc.spawnpadsperteam[g_ScenarioData.ctc.teamindexes[index]].numspawnpads);
return true;
}
return false;
}
s32 ctcGetMaxTeams(void)
{
return 4;
}
bool ctcIsRoomHighlighted(s16 room)
{
s32 i;
for (i = 0; i < 4; i++) {
if (g_ScenarioData.ctc.baserooms[i] == room && g_ScenarioData.ctc.teamindexes[i] != -1) {
return true;
}
}
return false;
}
void ctcHighlightRoom(s16 roomnum, s32 *arg1, s32 *arg2, s32 *arg3)
{
s32 i;
for (i = 0; i < 4; i++) {
if (g_ScenarioData.ctc.baserooms[i] == roomnum) {
u32 colour = g_TeamColours[i];
f32 a = *arg1;
f32 b = *arg2;
f32 c = *arg3;
a *= (s32)((colour >> 24 & 0xff) + 0xff) * (1.0f / 512.0f);
b *= (s32)((colour >> 16 & 0xff) + 0xff) * (1.0f / 512.0f);
c *= (s32)((colour >> 8 & 0xff) + 0xff) * (1.0f / 512.0f);
*arg1 = a;
*arg2 = b;
*arg3 = c;
return;
}
}
}

View File

@ -0,0 +1,31 @@
/**
* Combat
*
* This is a general combat scenario.
*
* There are no callback functions or special logic.
*/
struct menuitem g_MpCombatOptionsMenuItems[] = {
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_222, MPOPTION_ONEHITKILLS, menuhandlerMpOneHitKills }, // "One-Hit Kills"
{ MENUITEMTYPE_DROPDOWN, 0, 0x00020000, L_MPMENU_223, 0x00000000, menuhandlerMpSlowMotion }, // "Slow Motion"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_224, MPOPTION_FASTMOVEMENT, menuhandlerMpCheckboxOption }, // "Fast Movement"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_225, MPOPTION_DISPLAYTEAM, menuhandlerMpDisplayTeam }, // "Display Team"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_226, MPOPTION_NORADAR, menuhandlerMpCheckboxOption }, // "No Radar"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_227, MPOPTION_NOAUTOAIM, menuhandlerMpCheckboxOption }, // "No Auto-Aim"
{ MENUITEMTYPE_SEPARATOR, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_228, MPOPTION_NOPLAYERHIGHLIGHT, menuhandlerMpCheckboxOption }, // "No Player Highlight"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_229, MPOPTION_NOPICKUPHIGHLIGHT, menuhandlerMpCheckboxOption }, // "No Pickup Highlight"
{ MENUITEMTYPE_SEPARATOR, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
{ MENUITEMTYPE_SELECTABLE, 0, 0x00000008, L_MPMENU_239, 0x00000000, NULL }, // "Back"
{ MENUITEMTYPE_END, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
};
struct menudialog g_MpCombatOptionsMenuDialog = {
MENUDIALOGTYPE_DEFAULT,
L_MPMENU_215, // "Combat Options"
g_MpCombatOptionsMenuItems,
mpOptionsMenuDialog,
0x00000010,
NULL,
};

View File

@ -0,0 +1,690 @@
/**
* Hack that Mac (also known as Hacker Central)
*
* A data uplink and a terminal are spawned into a random location in the arena.
* Players must pick up the data uplink then go to the terminal and download
* data from it to score points. Each download takes 20 seconds and the player
* cannot use weapons while uplinking.
*/
#define HTM_NUM_TERMINALS 1
struct menuitem g_HtmOptionsMenuItems[] = {
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_222, MPOPTION_ONEHITKILLS, menuhandlerMpOneHitKills }, // "One-Hit Kills"
{ MENUITEMTYPE_DROPDOWN, 0, 0x00020000, L_MPMENU_223, 0x00000000, menuhandlerMpSlowMotion }, // "Slow Motion"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_224, MPOPTION_FASTMOVEMENT, menuhandlerMpCheckboxOption }, // "Fast Movement"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_225, MPOPTION_DISPLAYTEAM, menuhandlerMpDisplayTeam }, // "Display Team"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_226, MPOPTION_NORADAR, menuhandlerMpCheckboxOption }, // "No Radar"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_227, MPOPTION_NOAUTOAIM, menuhandlerMpCheckboxOption }, // "No Auto-Aim"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_OPTIONS_493, MPOPTION_KILLSSCORE, menuhandlerMpCheckboxOption }, // "Kills Score"
{ MENUITEMTYPE_SEPARATOR, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_231, MPOPTION_HTM_HIGHLIGHTTERMINAL, menuhandlerMpCheckboxOption }, // "Highlight Terminal"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_238, MPOPTION_HTM_SHOWONRADAR, menuhandlerMpCheckboxOption }, // "Show on Radar"
{ MENUITEMTYPE_SEPARATOR, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
{ MENUITEMTYPE_SELECTABLE, 0, 0x00000008, L_MPMENU_239, 0x00000000, NULL }, // "Back"
{ MENUITEMTYPE_END, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
};
struct menudialog g_HtmOptionsMenuDialog = {
MENUDIALOGTYPE_DEFAULT,
L_MPMENU_217, // "Hacker Options"
g_HtmOptionsMenuItems,
mpOptionsMenuDialog,
0x00000010,
NULL,
};
struct weaponobj g_HtmUplinkObj;
void htmInit(void)
{
g_ScenarioData.htm.uplink = NULL;
}
/**
* Add one for the data uplink.
*/
s32 htmNumProps(void)
{
return HTM_NUM_TERMINALS + 1;
}
void htmAddPad(s16 padnum)
{
struct scenariodata_htm *data = &g_ScenarioData.htm;
#if VERSION >= VERSION_NTSC_1_0
if (data->numpads < ARRAYCOUNT(g_ScenarioData.htm.padnums))
#endif
{
osSyncPrintf("HackThatMacAddBankPad -> Adding New Pad %d - Pad Id = %d-> Saving Pad\n", data->numpads, padnum);
data->padnums[data->numpads] = padnum;
data->numpads++;
}
}
void htmReset(void)
{
s32 i;
osSyncPrintf("HackThatMacReset -> Working\n");
g_ScenarioData.htm.numpads = 0;
g_ScenarioData.htm.numterminals = 0;
g_ScenarioData.htm.unk138 = 0;
g_ScenarioData.htm.dlplayernum = -1;
g_ScenarioData.htm.playernuminrange = -1;
g_ScenarioData.htm.dlterminalnum = -1;
g_ScenarioData.htm.unk140 = 0;
for (i = 0; i < ARRAYCOUNT(g_ScenarioData.htm.numpoints); i++) {
g_ScenarioData.htm.numpoints[i] = 0;
g_ScenarioData.htm.dltime240[i] = 0;
}
for (i = 0; i < ARRAYCOUNT(g_ScenarioData.htm.padnums); i++) {
g_ScenarioData.htm.padnums[i] = -1;
}
for (i = 0; i < HTM_NUM_TERMINALS; i++) {
g_ScenarioData.htm.terminals[i].unk00 = 0;
g_ScenarioData.htm.terminals[i].prop = NULL;
g_ScenarioData.htm.terminals[i].padnum = -1;
g_ScenarioData.htm.terminals[i].team = 255;
g_ScenarioData.htm.terminals[i].unk0b = 255;
}
}
void htbCreateUplink(void)
{
struct weaponobj template = {
512, // extrascale
0, // hidden2
OBJTYPE_WEAPON, // type
MODEL_CHRDATATHIEF, // modelnum
0, // pad
OBJFLAG_00000001 | OBJFLAG_INVINCIBLE | OBJFLAG_00400000,
OBJFLAG2_IMMUNETOGUNFIRE | OBJFLAG2_00200000,
0, // flags3
NULL, // prop
NULL, // model
1, 0, 0, // realrot
0, 1, 0,
0, 0, 1,
0, // hidden
NULL, // geo
NULL, // projectile
0, // damage
1000, // maxdamage
0xff, 0xff, 0xff, 0x00, // shadecol
0xff, 0xff, 0xff, 0x00, // nextcol
0x0fff, // floorcol
0, // tiles
WEAPON_DATAUPLINK, // weaponnum
0, // unk5d
0, // unk5e
FUNC_PRIMARY, // gunfunc
0, // fadeouttimer60
-1, // dualweaponnum
-1, // timer240
NULL, // dualweapon
};
struct prop *prop = g_Vars.activeprops;
struct defaultobj *obj;
s32 padnum;
s32 count = 0;
struct defaultobj *candidates[20];
while (prop && count < 20) {
#if VERSION >= VERSION_NTSC_1_0
if (prop->type == PROPTYPE_OBJ)
#endif
{
obj = prop->obj;
if (obj->type == OBJTYPE_MULTIAMMOCRATE) {
candidates[count] = obj;
count++;
}
}
prop = prop->next;
}
if (count > 0) {
count = random() % count;
var800869ec = candidates[count];
var800869ec->hidden |= OBJHFLAG_REAPABLE;
var800869ec->hidden2 |= OBJH2FLAG_CANREGEN;
padnum = var800869ec->pad;
} else if (g_ScenarioData.htm.numpads > 0) {
padnum = g_ScenarioData.htm.padnums[random() % g_ScenarioData.htm.numpads];
} else {
padnum = 0;
}
g_HtmUplinkObj = template;
g_HtmUplinkObj.base.pad = padnum;
weaponAssignToHome(&g_HtmUplinkObj, 999);
g_HtmUplinkObj.base.hidden2 &= ~OBJH2FLAG_CANREGEN;
g_ScenarioData.htm.uplink = g_HtmUplinkObj.base.prop;
if (g_ScenarioData.htm.uplink) {
g_ScenarioData.htm.uplink->forcetick = true;
}
}
void htmInitProps(void)
{
struct scenariodata_htm *data = &g_ScenarioData.htm;
struct prop *prop = g_Vars.activeprops;
s32 i = 0;
s32 rand;
osSyncPrintf("HackThatMacInitProps -> Start : %d Bank Pads\n", data->numterminals);
while (prop) {
if (prop->type == PROPTYPE_OBJ) {
struct defaultobj *obj = prop->obj;
if (obj->type == OBJTYPE_AMMOCRATE || obj->type == OBJTYPE_MULTIAMMOCRATE) {
if (obj->modelnum == MODEL_MULTI_AMMO_CRATE) {
osSyncPrintf("HackThatMacInitProps -> Adding prop %d (%x)\n", i, obj->pad);
htmAddPad(obj->pad);
}
}
}
prop = prop->next;
i++;
}
osSyncPrintf("HackThatMacInitProps -> Mid : %d Bank Pads\n", data->numpads);
osSyncPrintf("HackThatMacInitProps -> Generating %d random box pads from %d in the bank\n", htmNumProps(), data->numpads);
data->numterminals = 0;
// @bug: This should be < htmNumProps() - 1 to account for the data uplink,
// or just < HTM_NUM_TERMINALS. If HTM_NUM_TERMINALS is set to 7 then it
// will overflow the array.
while (data->numterminals < htmNumProps()) {
s32 padnum;
do {
rand = random() % data->numpads;
padnum = data->padnums[rand];
} while (padnum <= 0);
data->terminals[data->numterminals].padnum = padnum;
data->numterminals++;
data->padnums[rand] = -1;
}
osSyncPrintf("HackThatMacInitProps -> %d/%d Random box pads generated - Listing\n", data->numterminals, htmNumProps());
for (i = 0; i < data->numterminals; i++) {
osSyncPrintf("Pad %d -> Pad Id = %d\n", i, data->terminals[i].padnum);
}
for (i = 0; i < HTM_NUM_TERMINALS; i++) {
data->terminals[i].prop = scenarioCreateObj(MODEL_GOODPC, data->terminals[i].padnum, 0.2f,
OBJFLAG_00000001 | OBJFLAG_INVINCIBLE | OBJFLAG_00400000,
OBJFLAG2_IMMUNETOGUNFIRE | OBJFLAG2_00200000,
OBJFLAG3_HTMTERMINAL | OBJFLAG3_INTERACTABLE);
osSyncPrintf("HackThatMacInitProps -> Building and adding custom prop %d - Pad=%d, Ptr=%08x\n",
i, data->terminals[i].padnum, data->terminals[i].prop);
htbRemoveAmmoCrateAtPad(data->terminals[i].padnum);
}
var800869ec = NULL;
htbCreateUplink();
osSyncPrintf("HackThatMacInitProps -> End\n");
}
void htmTick(void)
{
u8 stack[8];
s32 i;
u32 prevplayernum = g_Vars.currentplayernum;
struct prop *prop;
if (var800869ec && var800869ec->prop) {
if (g_ScenarioData.htm.uplink == NULL || g_ScenarioData.htm.uplink->type != PROPTYPE_WEAPON) {
var800869ec = NULL;
} else {
var800869ec->prop->timetoregen = PALDOWN(1200);
}
}
g_ScenarioData.htm.uplink = NULL;
// Check if uplink is on the ground
prop = g_Vars.activeprops;
while (prop) {
if (prop->type == PROPTYPE_WEAPON) {
struct weaponobj *weapon = prop->weapon;
if (weapon->weaponnum == WEAPON_DATAUPLINK) {
g_ScenarioData.htm.uplink = prop;
}
}
prop = prop->next;
}
// Check if a player is holding it
if (g_ScenarioData.htm.uplink == NULL) {
for (i = 0; i < PLAYERCOUNT(); i++) {
setCurrentPlayerNum(i);
if (invHasDataUplink()) {
g_ScenarioData.htm.uplink = g_Vars.currentplayer->prop;
break;
}
}
}
setCurrentPlayerNum(prevplayernum);
// Check if a simulant is holding it
if (g_ScenarioData.htm.uplink == NULL) {
for (i = PLAYERCOUNT(); i < g_MpNumChrs; i++) {
if (g_MpAllChrPtrs[i]->aibot->hasuplink) {
g_ScenarioData.htm.uplink = g_MpAllChrPtrs[i]->prop;
break;
}
}
}
if (g_ScenarioData.htm.uplink == NULL) {
htbCreateUplink();
}
}
void htmTickChr(struct chrdata *chr)
{
struct scenariodata_htm *data = &g_ScenarioData.htm;
bool hasuplink;
s32 playernum;
s32 i;
s32 *time;
if (chr) {
hasuplink = chr->aibot->hasuplink;
playernum = mpPlayerGetIndex(chr);
} else {
hasuplink = invHasDataUplink() && bgunGetWeaponNum(HAND_RIGHT) == WEAPON_DATAUPLINK;
playernum = g_Vars.currentplayernum;
}
time = &data->dltime240[playernum];
for (i = 0; i < HTM_NUM_TERMINALS; i++) {
if (data->terminals[i].prop) {
struct prop *prop = data->terminals[i].prop;
struct defaultobj *obj = prop->obj;
s32 activatedbyplayernum = -1;
if (chr) {
if (hasuplink) {
activatedbyplayernum = playernum;
}
} else {
if (obj->hidden & OBJHFLAG_ACTIVATED_BY_BOND) {
activatedbyplayernum = (obj->hidden & 0xf0000000) >> 28;
}
}
if (playernum == activatedbyplayernum) {
obj->hidden &= ~OBJHFLAG_ACTIVATED_BY_BOND;
obj->hidden &= ~0xf0000000;
if (hasuplink) {
if (data->dlterminalnum == -1) {
data->dlterminalnum = i;
data->dlplayernum = playernum;
data->playernuminrange = playernum;
*time = 0;
if (chr == NULL) {
hudmsgCreateWithFlags(langGet(L_MPWEAPONS_018), HUDMSGTYPE_MPSCENARIO, HUDMSGFLAG_ONLYIFALIVE); // "Starting download."
func0f0939f8(NULL, data->terminals[data->dlterminalnum].prop, SFX_01BF, -1,
-1, 2, 2, 0, NULL, -1, NULL, -1, -1, -1, -1);
}
}
} else {
if (chr == NULL) {
hudmsgCreateWithFlags(langGet(L_MPWEAPONS_019), HUDMSGTYPE_MPSCENARIO, HUDMSGFLAG_ONLYIFALIVE); // "You need to use the Data Uplink."
snd00010718(NULL, 0, 0x7fff, 0x40, SFX_01CC, 1, 1, -1, 1);
}
}
}
}
}
if (playernum == data->dlplayernum && data->dlterminalnum != -1) {
struct coord *terminalpos = &data->terminals[data->dlterminalnum].prop->pos;
f32 angle;
f32 relangle;
f32 rangexz;
f32 rangey;
struct coord *chrpos;
struct coord dist;
bool holdinguplink;
if (chr) {
chrpos = &chr->prop->pos;
angle = (M_BADTAU - chrGetInverseTheta(chr)) * 57.295776367188f;
holdinguplink = chr->aibot->weaponnum == WEAPON_UNARMED;
} else {
chrpos = &g_Vars.currentplayer->prop->pos;
angle = g_Vars.currentplayer->vv_theta;
holdinguplink = bgunGetWeaponNum(HAND_RIGHT) == WEAPON_DATAUPLINK;
}
dist.x = terminalpos->x - chrpos->x;
dist.y = terminalpos->y - chrpos->y;
dist.z = terminalpos->z - chrpos->z;
rangexz = sqrtf(dist.x * dist.x + dist.z * dist.z);
rangey = ABS(dist.y);
relangle = atan2f(dist.x, dist.z) * 57.295776367188f + angle;
while (relangle < 180) {
relangle += 360;
}
while (relangle > 180) {
relangle -= 360;
}
if (relangle > 0) {
// empty
} else {
relangle = -relangle;
}
osSyncPrintf("HTM : Player %d - Term Pos = (%d,%d,%d)", playernum, (s32)terminalpos->x, (s32)terminalpos->y, (s32)terminalpos->z);
osSyncPrintf("HTM : Player %d - Play Pos = (%d,%d,%d)", playernum, (s32)chrpos->x, (s32)chrpos->y, (s32)chrpos->z);
osSyncPrintf("HTM : Player %d - T/P Rel = (%d,%d,%d)", playernum, (s32)dist.x, (s32)dist.y, (s32)dist.z);
osSyncPrintf("HTM : Player %d - Range XZ = %d", playernum, rangexz);
osSyncPrintf("HTM : Player %d - Range Y = %d", playernum, rangey);
osSyncPrintf("HTM : Player %d - Angle XZ = %d", playernum, relangle);
if (rangexz > 250 || rangey > 200 || relangle > 45 || !holdinguplink) {
if (rangexz < 250 && rangey < 200) {
data->playernuminrange = playernum;
} else {
data->playernuminrange = -1;
}
if (chr == NULL) {
// "Connection broken."
hudmsgCreateWithFlags(langGet(L_MPWEAPONS_017), HUDMSGTYPE_MPSCENARIO, HUDMSGFLAG_ONLYIFALIVE);
func0f0926bc(data->terminals[data->dlterminalnum].prop, 1, 0xffff);
snd00010718(NULL, 0, 0x7fff, 0x40, SFX_01CC, 1, 1, -1, 1);
}
data->dlterminalnum = -1;
data->dlplayernum = -1;
*time = 0;
} else {
*time += g_Vars.lvupdate240;
if (*time > 20 * PALDOWN(240)) {
data->numpoints[playernum]++;
data->playernuminrange = playernum;
if (chr == NULL) {
// "Download successful."
hudmsgCreateWithFlags(langGet(L_MPWEAPONS_016), HUDMSGTYPE_MPSCENARIO, HUDMSGFLAG_ONLYIFALIVE);
func0f0926bc(data->terminals[data->dlterminalnum].prop, 1, 0xffff);
snd00010718(NULL, 0, 0x7fff, 0x40, SFX_01C1, 1, 1, -1, 1);
}
data->dlterminalnum = -1;
data->dlplayernum = -1;
*time = 0;
}
}
osSyncPrintf("HTM : Player %d - Dwnld Plr=%d, Dwnld Prop=%d\n", playernum, data->playernuminrange, data->terminals[data->dlterminalnum].prop);
osSyncPrintf("HTM : Player %d - Download Time = %d", playernum, *time);
}
}
Gfx *htmRenderHud(Gfx *gdl)
{
struct scenariodata_htm *data = &g_ScenarioData.htm;
s32 dltime;
s32 viewleft;
s32 viewright;
s32 viewtop;
s32 a0;
s32 a1;
s32 barleft;
s32 barright;
s32 t1;
s32 t6;
s32 v1;
s32 s1;
dltime = data->dltime240[g_Vars.currentplayernum];
if (data->dlterminalnum != -1 && g_Vars.currentplayernum == data->dlplayernum) {
viewleft = viGetViewLeft();
viewright = viGetViewLeft() + viGetViewWidth();
viewtop = viGetViewTop();
t6 = (viewleft + viewright) / 2;
a1 = viGetViewWidth() / 3;
barleft = t6 - a1 / 2;
barright = t6 + a1 / 2;
s1 = barleft + (s32) (a1 * (dltime / PALDOWN(4800.0f)));
gdl = func0f153628(gdl);
gdl = gfxSetPrimColour(gdl, 0x60000060);
gDPFillRectangle(gdl++, barleft, viewtop + 8, barright, viewtop + 16);
gdl = func0f153838(gdl);
gdl = gfxSetPrimColour(gdl, 0xc00000d0);
v1 = barleft + 1;
a0 = barleft;
while (v1 < s1) {
gDPFillRectangle(gdl++, a0, viewtop + 8, v1, viewtop + 16);
v1 += 2;
a0 += 2;
}
gdl = func0f153838(gdl);
gdl = func0f153780(gdl);
}
return gdl;
}
void htmCalculatePlayerScore(struct mpchrconfig *mpchr, s32 mpchrnum, s32 *score, s32 *deaths)
{
struct mpchrconfig *loopmpchr;
s32 i;
s32 index;
*score = 0;
index = func0f18d0e8(mpchrnum);
if (index >= 0) {
*score += g_ScenarioData.htm.numpoints[index] * 2;
}
if (g_MpSetup.options & MPOPTION_KILLSSCORE) {
for (i = 0; i != MAX_MPCHRS; i++) {
if (i == mpchrnum) {
*score -= mpchr->killcounts[i];
} else if (g_MpSetup.options & MPOPTION_TEAMSENABLED) {
loopmpchr = MPCHR(i);
if (loopmpchr->team == mpchr->team) {
*score -= mpchr->killcounts[i];
} else {
*score += mpchr->killcounts[i];
}
} else {
*score += mpchr->killcounts[i];
}
}
}
*deaths = mpchr->numdeaths;
}
Gfx *htmRadarExtra(Gfx *gdl)
{
struct scenariodata_htm *data = &g_ScenarioData.htm;
struct coord dist;
s32 i;
struct coord sp88;
// Red/green/blue/alpha as float and integer
f32 rf;
f32 gf;
f32 bf;
f32 af;
u32 ri;
u32 gi;
u32 bi;
u32 ai;
if (g_MpSetup.options & MPOPTION_HTM_SHOWONRADAR) {
// Show the uplink
if (data->uplink && data->uplink->type != PROPTYPE_PLAYER && data->uplink->type != PROPTYPE_CHR) {
dist.x = data->uplink->pos.x - g_Vars.currentplayer->prop->pos.x;
dist.y = data->uplink->pos.y - g_Vars.currentplayer->prop->pos.y;
dist.z = data->uplink->pos.z - g_Vars.currentplayer->prop->pos.z;
gdl = radarDrawDot(gdl, data->uplink, &dist, 0x00ff0000, 0x00000000, true);
}
// Show the terminal
for (i = 0; i < HTM_NUM_TERMINALS; i++) {
if (data->terminals[i].prop) {
sp88.x = data->terminals[i].prop->pos.x - g_Vars.currentplayer->prop->pos.x;
sp88.y = data->terminals[i].prop->pos.y - g_Vars.currentplayer->prop->pos.y;
sp88.z = data->terminals[i].prop->pos.z - g_Vars.currentplayer->prop->pos.z;
if (data->terminals[i].team == 255) {
rf = 0;
gf = 255;
bf = 0;
af = 0;
} else if (g_MpSetup.options & MPOPTION_TEAMSENABLED) {
u32 colour = g_TeamColours[radarGetTeamIndex(data->terminals[i].team)];
rf = (colour >> 24) & 0xff;
gf = ((colour >> 16) & 0xff);
bf = ((colour >> 8) & 0xff);
af = colour & 0xff;
} else {
rf = 0;
gf = 255;
bf = 0;
af = 0;
}
ri = rf;
gi = gf;
bi = bf;
ai = af;
if (ri > 255) {
ri = 255;
}
if (gi > 255) {
gi = 255;
}
if (bi > 255) {
bi = 255;
}
if (ai > 255) {
ai = 255;
}
gdl = radarDrawDot(gdl, data->terminals[i].prop, &sp88,
(ri << 24) | (gi << 16) | (bi << 8) | ai,
0x00000000, true);
}
}
}
return gdl;
}
bool htmRadarChr(Gfx **gdl, struct prop *prop)
{
if ((g_MpSetup.options & MPOPTION_HTM_SHOWONRADAR) && g_ScenarioData.htm.uplink) {
if (prop == g_ScenarioData.htm.uplink &&
(prop->type == PROPTYPE_PLAYER || prop->type == PROPTYPE_CHR)) {
struct coord dist;
dist.x = prop->pos.x - g_Vars.currentplayer->prop->pos.x;
dist.y = prop->pos.y - g_Vars.currentplayer->prop->pos.y;
dist.z = prop->pos.z - g_Vars.currentplayer->prop->pos.z;
if (g_MpSetup.options & MPOPTION_TEAMSENABLED) {
u32 colour = g_TeamColours[radarGetTeamIndex(prop->chr->team)];
*gdl = radarDrawDot(*gdl, g_ScenarioData.htm.uplink, &dist, colour, 0, 1);
} else {
*gdl = radarDrawDot(*gdl, g_ScenarioData.htm.uplink, &dist, 0x00ff0000, 0, 1);
}
return true;
}
}
return false;
}
bool htmHighlightProp(struct prop *prop, s32 *colour)
{
if (g_MpSetup.options & MPOPTION_HTM_HIGHLIGHTTERMINAL) {
bool highlight = false;
if (prop == g_ScenarioData.htm.uplink) {
highlight = true;
} else {
s32 i;
for (i = 0; i < HTM_NUM_TERMINALS; i++) {
if (g_ScenarioData.htm.terminals[i].prop == prop) {
highlight = true;
break;
}
}
}
if (highlight) {
colour[0] = 0;
colour[1] = 0xff;
colour[2] = 0;
colour[3] = 0x40;
return true;
}
}
return false;
}

View File

@ -0,0 +1,434 @@
/**
* Hold the Briefcase
*
* A briefcase is spawned into a random location in the arena. Players must pick
* up the briefcase and then stay alive for as long as possible. The player
* scores a point every 30 seconds while the briefcase is held.
*
* While holding the briefcase, the player cannot pick up shields. The move
* slightly slower but still have full access to their weaponry.
*/
struct menuitem g_HtbOptionsMenuItems[] = {
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_222, MPOPTION_ONEHITKILLS, menuhandlerMpOneHitKills }, // "One-Hit Kills"
{ MENUITEMTYPE_DROPDOWN, 0, 0x00020000, L_MPMENU_223, 0x00000000, menuhandlerMpSlowMotion }, // "Slow Motion"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_224, MPOPTION_FASTMOVEMENT, menuhandlerMpCheckboxOption }, // "Fast Movement"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_225, MPOPTION_DISPLAYTEAM, menuhandlerMpDisplayTeam }, // "Display Team"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_226, MPOPTION_NORADAR, menuhandlerMpCheckboxOption }, // "No Radar"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_227, MPOPTION_NOAUTOAIM, menuhandlerMpCheckboxOption }, // "No Auto-Aim"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_OPTIONS_493, MPOPTION_KILLSSCORE, menuhandlerMpCheckboxOption }, // "Kills Score"
{ MENUITEMTYPE_SEPARATOR, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_237, MPOPTION_HTB_HIGHLIGHTBRIEFCASE, menuhandlerMpCheckboxOption }, // "Highlight Briefcase"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_238, MPOPTION_HTB_SHOWONRADAR, menuhandlerMpCheckboxOption }, // "Show on Radar"
{ MENUITEMTYPE_SEPARATOR, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
{ MENUITEMTYPE_SELECTABLE, 0, 0x00000008, L_MPMENU_239, 0x00000000, NULL }, // "Back"
{ MENUITEMTYPE_END, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
};
struct menudialog g_HtbOptionsMenuDialog = {
MENUDIALOGTYPE_DEFAULT,
L_MPMENU_216, // "Briefcase Options"
g_HtbOptionsMenuItems,
mpOptionsMenuDialog,
0x00000010,
NULL,
};
struct defaultobj *var800869ec = NULL;
struct weaponobj g_HtbTokenObj;
void htbInit(void)
{
g_ScenarioData.htb.token = NULL;
}
void htbAddPad(s16 padnum)
{
struct scenariodata_htb *data = &g_ScenarioData.htb;
#if VERSION >= VERSION_NTSC_1_0
if (data->nextindex < ARRAYCOUNT(data->padnums))
#endif
{
osSyncPrintf("CaptureTheBriefcaseAddBankPad -> Adding New Pad %d - Pad Id = %d-> Saving Pad\n", data->nextindex, padnum);
data->padnums[data->nextindex] = padnum;
data->nextindex++;
}
}
s32 htbNumProps(void)
{
return 1;
}
void htbRemoveAmmoCrateAtPad(s16 padnum)
{
struct prop *prop = g_Vars.activeprops;
while (prop) {
if (prop->type == PROPTYPE_OBJ) {
struct defaultobj *obj = prop->obj;
if (obj->pad == padnum
&& (obj->type == OBJTYPE_AMMOCRATE || obj->type == OBJTYPE_MULTIAMMOCRATE)
&& obj->modelnum == MODEL_MULTI_AMMO_CRATE) {
obj->hidden |= OBJHFLAG_REAPABLE;
obj->hidden2 &= ~OBJH2FLAG_CANREGEN;
return;
}
}
prop = prop->next;
}
}
void htbReset(void)
{
s32 i;
g_ScenarioData.htb.nextindex = 0;
for (i = 0; i < ARRAYCOUNT(g_ScenarioData.htb.padnums); i++) {
g_ScenarioData.htb.padnums[i] = -1;
}
}
void htbCreateToken(void)
{
struct weaponobj template = {
256, // extrascale
0, // hidden2
OBJTYPE_WEAPON, // type
MODEL_CHRBRIEFCASE, // modelnum
0, // pad
OBJFLAG_00000001 | OBJFLAG_INVINCIBLE | OBJFLAG_00400000,
OBJFLAG2_IMMUNETOGUNFIRE | OBJFLAG2_00200000,
0, // flags3
NULL, // prop
NULL, // model
1, 0, 0, // realrot
0, 1, 0,
0, 0, 1,
0, // hidden
NULL, // geo
NULL, // projectile
0, // damage
1000, // maxdamage
0xff, 0xff, 0xff, 0x00, // shadecol
0xff, 0xff, 0xff, 0x00, // nextcol
0x0fff, // floorcol
0, // tiles
WEAPON_BRIEFCASE2, // weaponnum
0, // unk5d
0, // unk5e
FUNC_PRIMARY, // gunfunc
0, // fadeouttimer60
-1, // dualweaponnum
-1, // timer240
NULL, // dualweapon
};
struct prop *prop = g_Vars.activeprops;
struct defaultobj *obj;
s32 count = 0;
struct defaultobj *candidates[20];
// Build a list of candidate objects to replace. Consider only ammocrates.
// NTSC beta doesn't check the prop type, so it could potentially replace a
// player, bot, explosion or smoke.
while (prop && count < 20) {
#if VERSION >= VERSION_NTSC_1_0
if (prop->type == PROPTYPE_OBJ)
#endif
{
obj = prop->obj;
if (obj->type == OBJTYPE_MULTIAMMOCRATE) {
candidates[count] = obj;
count++;
}
}
prop = prop->next;
}
// Choose the candidate and remove it
if (count > 0) {
count = random() % count;
var800869ec = candidates[count];
g_ScenarioData.htb.tokenpad = var800869ec->pad;
var800869ec->hidden |= OBJHFLAG_REAPABLE;
var800869ec->hidden2 |= OBJH2FLAG_CANREGEN;
} else if (g_ScenarioData.htb.nextindex > 0) {
g_ScenarioData.htb.tokenpad = g_ScenarioData.htb.padnums[random() % g_ScenarioData.htb.nextindex];
} else {
g_ScenarioData.htb.tokenpad = 0;
}
// Set up the token
g_HtbTokenObj = template;
g_HtbTokenObj.base.pad = g_ScenarioData.htb.tokenpad;
weaponAssignToHome(&g_HtbTokenObj, 999);
g_HtbTokenObj.base.hidden2 &= ~OBJH2FLAG_CANREGEN;
g_ScenarioData.htb.token = g_HtbTokenObj.base.prop;
if (g_ScenarioData.htb.token) {
g_ScenarioData.htb.token->forcetick = true;
}
}
void htbInitProps(void)
{
var800869ec = NULL;
htbCreateToken();
}
void htbTick(void)
{
s32 i;
u32 prevplayernum = g_Vars.currentplayernum;
struct prop *prop;
if (var800869ec && var800869ec->prop) {
if (g_ScenarioData.htb.token == NULL || g_ScenarioData.htb.token->type != PROPTYPE_WEAPON) {
var800869ec = NULL;
} else {
var800869ec->prop->timetoregen = PALDOWN(1200);
}
}
g_ScenarioData.htb.token = NULL;
// Check if briefcase is on the ground
prop = g_Vars.activeprops;
while (prop) {
if (prop->type == PROPTYPE_WEAPON) {
struct weaponobj *weapon = prop->weapon;
if (weapon->weaponnum == WEAPON_BRIEFCASE2) {
g_ScenarioData.htb.token = prop;
}
}
prop = prop->next;
}
// Check if a player is holding it
if (g_ScenarioData.htb.token == NULL) {
for (i = 0; i < PLAYERCOUNT(); i++) {
setCurrentPlayerNum(i);
if (invHasBriefcase()) {
g_ScenarioData.htb.token = g_Vars.currentplayer->prop;
break;
}
}
}
setCurrentPlayerNum(prevplayernum);
// Check if a simulant is holding it
if (g_ScenarioData.htb.token == NULL) {
for (i = PLAYERCOUNT(); i < g_MpNumChrs; i++) {
#if VERSION >= VERSION_NTSC_1_0
if (g_MpAllChrPtrs[i]->prop && g_MpAllChrPtrs[i]->aibot->hasbriefcase)
#else
if (g_MpAllChrPtrs[i]->aibot->hasbriefcase)
#endif
{
g_ScenarioData.htb.token = g_MpAllChrPtrs[i]->prop;
break;
}
}
}
if (g_ScenarioData.htb.token == NULL) {
htbCreateToken();
}
if (g_ScenarioData.htb.token == NULL) {
g_ScenarioData.htb.pos.x = 0;
g_ScenarioData.htb.pos.y = 0;
g_ScenarioData.htb.pos.z = 0;
} else {
struct coord *pos = &g_ScenarioData.htb.pos;
pos->x = g_ScenarioData.htb.token->pos.x;
pos->y = g_ScenarioData.htb.token->pos.y;
pos->z = g_ScenarioData.htb.token->pos.z;
}
}
void htbTickChr(struct chrdata *chr)
{
if (chr) {
if (chr->aibot->hasbriefcase) {
chr->aibot->unk0a0 += g_Vars.lvupdate240;
if (chr->aibot->unk0a0 >= PALDOWN(7200)) {
sndStart(var80095200, SFX_MP_SCOREPOINT, NULL, -1, -1, -1, -1, -1);
g_MpAllChrConfigPtrs[mpPlayerGetIndex(chr)]->numpoints++;
chr->aibot->unk0a0 = 0;
}
} else {
chr->aibot->unk0a0 = 0;
}
} else {
if (invHasBriefcase()) {
g_Vars.currentplayerstats->tokenheldtime += g_Vars.lvupdate240;
if (g_Vars.currentplayerstats->tokenheldtime >= PALDOWN(7200)) {
sndStart(var80095200, SFX_MP_SCOREPOINT, NULL, -1, -1, -1, -1, -1);
g_MpAllChrConfigPtrs[g_Vars.currentplayernum]->numpoints++;
hudmsgCreateWithFlags(langGet(L_MPWEAPONS_024), HUDMSGTYPE_MPSCENARIO, HUDMSGFLAG_ONLYIFALIVE); // "1 Point!"
g_Vars.currentplayerstats->tokenheldtime = 0;
}
} else {
g_Vars.currentplayerstats->tokenheldtime = 0;
}
}
}
/**
* @bug: In NTSC Final, the calculation of mins and subsequent subtraction from
* time240 should use 60 * 240 instead of 30 * 240. This has no noticeable
* effect unless the score duration is increased to above 30 seconds.
*
* PAL recognises that mins will always be 0 and simplifies the calculation.
*/
Gfx *htbRenderHud(Gfx *gdl)
{
s32 time240;
s32 mins;
s32 secs;
s32 textwidth;
s32 textheight;
s32 x;
s32 y;
char text[64];
if (invHasBriefcase()) {
x = viGetViewLeft() + viGetViewWidth() / 2;
y = viGetViewTop() + 10;
#if VERSION >= VERSION_PAL_FINAL
time240 = (30 * 200) - g_Vars.currentplayerstats->tokenheldtime;
secs = (time240 + 199) / 200;
sprintf(text, "%d:%02d", 0, secs);
#else
time240 = (30 * 240) - g_Vars.currentplayerstats->tokenheldtime;
mins = time240 / (30 * 240);
time240 -= (30 * 240) * mins;
secs = (time240 + 239) / 240;
sprintf(text, "%d:%02d", mins, secs);
#endif
gdl = func0f153628(gdl);
textMeasure(&textheight, &textwidth, text, g_CharsHandelGothicXs, g_FontHandelGothicXs, 0);
x -= textwidth / 2;
textwidth += x;
textheight += y;
#if VERSION >= VERSION_NTSC_1_0
gdl = func0f153990(gdl, x, y, textwidth, textheight);
gdl = textRender(gdl, &x, &y, text, g_CharsNumeric, g_FontNumeric, 0x00ff00a0, 0xa0, viGetWidth(), viGetHeight(), 0, 0);
#else
gdl = func0f153858(gdl, &x, &y, &textwidth, &textheight);
gdl = textRender(gdl, &x, &y, text, g_CharsNumeric, g_FontNumeric, 0x00ff00a0, 0x88, viGetWidth(), viGetHeight(), 0, 0);
#endif
gdl = func0f153780(gdl);
}
return gdl;
}
void htbCalculatePlayerScore(struct mpchrconfig *mpchr, s32 mpchrnum, s32 *score, s32 *deaths)
{
struct mpchrconfig *loopmpchr;
s32 i;
*score = 0;
*score += mpchr->numpoints;
if (g_MpSetup.options & MPOPTION_KILLSSCORE) {
for (i = 0; i != MAX_MPCHRS; i++) {
if (i == mpchrnum) {
*score -= mpchr->killcounts[i];
} else if (g_MpSetup.options & MPOPTION_TEAMSENABLED) {
loopmpchr = MPCHR(i);
if (loopmpchr->team == mpchr->team) {
*score -= mpchr->killcounts[i];
} else {
*score += mpchr->killcounts[i];
}
} else {
*score += mpchr->killcounts[i];
}
}
}
*deaths = mpchr->numdeaths;
}
Gfx *htbRadarExtra(Gfx *gdl)
{
if ((g_MpSetup.options & MPOPTION_HTB_SHOWONRADAR) &&
g_ScenarioData.htb.token != NULL &&
g_ScenarioData.htb.token->type != PROPTYPE_PLAYER &&
g_ScenarioData.htb.token->type != PROPTYPE_CHR) {
struct coord dist;
dist.x = g_ScenarioData.htb.pos.x - g_Vars.currentplayer->prop->pos.x;
dist.y = g_ScenarioData.htb.pos.y - g_Vars.currentplayer->prop->pos.y;
dist.z = g_ScenarioData.htb.pos.z - g_Vars.currentplayer->prop->pos.z;
gdl = radarDrawDot(gdl, g_ScenarioData.htb.token, &dist, 0x00ff0000, 0, 1);
}
return gdl;
}
bool htbRadarChr(Gfx **gdl, struct prop *prop)
{
if ((g_MpSetup.options & MPOPTION_HTB_SHOWONRADAR) &&
g_ScenarioData.htb.token &&
prop == g_ScenarioData.htb.token) {
if (prop->type == PROPTYPE_PLAYER || prop->type == PROPTYPE_CHR) {
struct coord dist;
dist.x = prop->pos.x - g_Vars.currentplayer->prop->pos.x;
dist.y = prop->pos.y - g_Vars.currentplayer->prop->pos.y;
dist.z = prop->pos.z - g_Vars.currentplayer->prop->pos.z;
if (g_MpSetup.options & MPOPTION_TEAMSENABLED) {
u32 colour = g_TeamColours[radarGetTeamIndex(prop->chr->team)];
*gdl = radarDrawDot(*gdl, g_ScenarioData.htb.token, &dist, colour, 0, 1);
} else {
*gdl = radarDrawDot(*gdl, g_ScenarioData.htb.token, &dist, 0x00ff0000, 0, 1);
}
return true;
}
}
return false;
}
bool htbHighlightProp(struct prop *prop, s32 *colour)
{
if ((g_MpSetup.options & MPOPTION_HTB_HIGHLIGHTBRIEFCASE) && prop == g_ScenarioData.htb.token) {
colour[0] = 0;
colour[1] = 0xff;
colour[2] = 0;
colour[3] = 0x40;
return true;
}
return false;
}

View File

@ -0,0 +1,571 @@
/**
* King of the Hill
*
* At the start of the match, a room is chosen as the "hill" and is highlighted
* in green. When a player enters the hill it changes to their team colour.
* If the player remains in the hill for the "mphilltime" (this is configurable)
* then they score a point and a new room is chosen as the next hill.
*
* If a second team enters the hill then the timer is paused until the hill is
* exclusive again. The enemy team must completely clear the hill of opposing
* players before it is switched to their team.
*
* Points are awarded to each player in the hill at the time that it is won.
*/
s32 menuhandlerMpHillTime(s32 operation, struct menuitem *item, union handlerdata *data)
{
switch (operation) {
case MENUOP_GETSLIDER:
data->slider.value = g_Vars.mphilltime;
break;
case MENUOP_SET:
g_Vars.mphilltime = (u8)data->slider.value;
break;
case MENUOP_GETSLIDERLABEL:
sprintf(data->slider.label, langGet(L_MPWEAPONS_023), data->slider.value + 10); // "%ds/Point"
break;
}
return 0;
}
struct menuitem g_KohOptionsMenuItems[] = {
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_222, MPOPTION_ONEHITKILLS, menuhandlerMpOneHitKills }, // "One-Hit Kills"
{ MENUITEMTYPE_DROPDOWN, 0, 0x00020000, L_MPMENU_223, 0x00000000, menuhandlerMpSlowMotion }, // "Slow Motion"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_224, MPOPTION_FASTMOVEMENT, menuhandlerMpCheckboxOption }, // "Fast Movement"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_225, MPOPTION_DISPLAYTEAM, menuhandlerMpDisplayTeam }, // "Display Team"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_226, MPOPTION_NORADAR, menuhandlerMpCheckboxOption }, // "No Radar"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_227, MPOPTION_NOAUTOAIM, menuhandlerMpCheckboxOption }, // "No Auto-Aim"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_OPTIONS_493, MPOPTION_KILLSSCORE, menuhandlerMpCheckboxOption }, // "Kills Score"
{ MENUITEMTYPE_SEPARATOR, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_233, MPOPTION_KOH_HILLONRADAR, menuhandlerMpCheckboxOption }, // "Hill on Radar"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_234, MPOPTION_KOH_MOBILEHILL, menuhandlerMpCheckboxOption }, // "Mobile Hill"
{ MENUITEMTYPE_SLIDER, 0, 0x00020000, L_MPMENU_235, 0x0000006e, menuhandlerMpHillTime }, // "Time"
{ MENUITEMTYPE_SEPARATOR, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
{ MENUITEMTYPE_SELECTABLE, 0, 0x00000008, L_MPMENU_239, 0x00000000, NULL }, // "Back"
{ MENUITEMTYPE_END, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
};
struct menudialog g_KohOptionsMenuDialog = {
MENUDIALOGTYPE_DEFAULT,
L_MPMENU_219, // "Hill Options"
g_KohOptionsMenuItems,
mpOptionsMenuDialog,
0x00000010,
NULL,
};
void kohReadSave(struct savebuffer *buffer)
{
g_Vars.mphilltime = savebufferReadBits(buffer, 8);
}
void kohWriteSave(struct savebuffer *buffer)
{
savebufferOr(buffer, g_Vars.mphilltime, 8);
}
void kohInit(void)
{
s32 i;
g_MpSetup.options |= MPOPTION_TEAMSENABLED;
g_ScenarioData.koh.hillindex = -1;
g_ScenarioData.koh.hillcount = 0;
g_ScenarioData.koh.unk00 = 0;
g_ScenarioData.koh.occupiedteam = -1;
g_ScenarioData.koh.elapsed240 = 0;
g_ScenarioData.koh.hillrooms[0] = -1;
g_ScenarioData.koh.hillrooms[1] = -1;
g_ScenarioData.koh.hillpos.x = 0;
g_ScenarioData.koh.hillpos.y = 0;
g_ScenarioData.koh.hillpos.z = 0;
g_ScenarioData.koh.colourfracr = 0.25;
g_ScenarioData.koh.colourfracg = 1;
g_ScenarioData.koh.colourfracb = 0.25;
for (i = 0; i < 9; i++) {
g_ScenarioData.koh.hillpads[i] = -1;
}
}
void kohInitProps(void)
{
s16 pad_id = 0;
struct pad pad;
if (g_ScenarioData.koh.hillcount > 1) {
g_ScenarioData.koh.hillindex = random() % g_ScenarioData.koh.hillcount;
pad_id = g_ScenarioData.koh.hillpads[g_ScenarioData.koh.hillindex];
} else {
// @bug: If a stage setup file only has one hill, pad_id is not assigned
// so it will always use the room that contains pad zero.
g_ScenarioData.koh.hillindex = 0;
}
padUnpack(pad_id, PADFIELD_POS | PADFIELD_ROOM, &pad);
g_ScenarioData.koh.hillrooms[0] = pad.room;
g_ScenarioData.koh.hillrooms[1] = -1;
g_ScenarioData.koh.hillpos.x = pad.pos.x;
g_ScenarioData.koh.hillpos.y = pad.pos.y;
g_ScenarioData.koh.hillpos.z = pad.pos.z;
g_ScenarioData.koh.hillpos.y = cd0002a36c(&g_ScenarioData.koh.hillpos, &g_ScenarioData.koh.hillrooms[0], 0, 0);
g_ScenarioData.koh.movehill = false;
roomSetLighting(g_ScenarioData.koh.hillrooms[0], LIGHTOP_5, 0, 0, 0);
}
/**
* A match for this function has only been possible by making heavy reuse of
* variables, but this impacts readability significantly.
*
* To make this code readable, constants have been used to map appropriate names
* to the underlying variable.
*/
void kohTick(void)
{
s32 i;
s32 hillteam;
s32 s1;
s32 s2;
s32 numchrsinhill;
s32 dualoccupancy;
s32 s0;
s32 previndex;
f32 targetr;
f32 targetg;
f32 targetb;
char text[64];
s32 teamsinhill[8];
struct pad pad;
struct prop *chrsinhill[12];
struct prop *prop;
struct chrdata *chr;
s32 padnum;
s32 teamindex;
#define hillteam s0
#define inhill s1
#define mostchrs s1
#define playernum1 s1
#define prevplayernum1 s1
#define numteamsinhill s2
#define prevplayernum2 s2
#define playernum2 s2
if (g_ScenarioData.koh.hillindex == -1) {
return;
}
dualoccupancy = 0;
if (g_ScenarioData.koh.movehill) {
// The hill is moving, but first it needs to be returned to the natural
// colour. This is done using a fade over several frames.
g_ScenarioData.koh.occupiedteam = -1;
g_ScenarioData.koh.elapsed240 = 0;
targetr = 1;
targetg = 1;
targetb = 1;
if (g_ScenarioData.koh.colourfracr >= .95f
&& g_ScenarioData.koh.colourfracg >= .95f
&& g_ScenarioData.koh.colourfracb >= .95f) {
// The old hill is now "natural enough" to set it back to full
// natural colour and actually choose a new hill.
roomSetLighting(g_ScenarioData.koh.hillrooms[0], 0, 0, 0, 0);
// Choose the new hill. Note that hillcount refers to the number of
// hill options, which is always >= 2.
padnum = 0;
if (g_ScenarioData.koh.hillcount >= 2) {
previndex = g_ScenarioData.koh.hillindex;
do {
g_ScenarioData.koh.hillindex = random() % g_ScenarioData.koh.hillcount;
} while (g_ScenarioData.koh.hillindex == previndex);
padnum = g_ScenarioData.koh.hillpads[g_ScenarioData.koh.hillindex];
} else {
g_ScenarioData.koh.hillindex = 0;
}
padUnpack(padnum, PADFIELD_POS | PADFIELD_ROOM, &pad);
g_ScenarioData.koh.hillrooms[0] = pad.room;
g_ScenarioData.koh.hillrooms[1] = -1;
g_ScenarioData.koh.hillpos.x = pad.pos.x;
g_ScenarioData.koh.hillpos.y = pad.pos.y;
g_ScenarioData.koh.hillpos.z = pad.pos.z;
g_ScenarioData.koh.hillpos.y = cd0002a36c(&g_ScenarioData.koh.hillpos, g_ScenarioData.koh.hillrooms, NULL, NULL);
roomSetLighting(g_ScenarioData.koh.hillrooms[0], 5, 0, 0, 0);
g_ScenarioData.koh.occupiedteam = -1;
g_ScenarioData.koh.elapsed240 = 0;
g_ScenarioData.koh.movehill = false;
}
} else {
// The hill is not moving on this frame
// Build an array of chr props who are in the hill
numchrsinhill = 0;
prop = g_Vars.activeprops;
while (prop) {
if (prop->type == PROPTYPE_PLAYER || prop->type == PROPTYPE_CHR) {
inhill = false;
if (prop->rooms[0] == g_ScenarioData.koh.hillrooms[0]) {
inhill = true;
}
if (inhill) {
chr = prop->chr;
if (!chrIsDead(chr)) {
chrsinhill[numchrsinhill] = prop;
numchrsinhill++;
}
}
}
prop = prop->next;
}
// Use the chrshillhill array to build an array of all teams who have
// chrs in the hill. During development, this array likely stored a
// count of that team's chrs but was later changed to just be 0 or 1
// to denote if they have any chrs in the hill.
for (s0 = 0; s0 < 8; s0++) {
teamsinhill[s0] = 0;
}
for (s0 = 0, numteamsinhill = 0; s0 < numchrsinhill; s0++) {
chr = chrsinhill[s0]->chr;
teamindex = radarGetTeamIndex(chr->team);
if (teamsinhill[teamindex] == 0) {
numteamsinhill++;
teamsinhill[teamindex] = 1;
}
}
if (numteamsinhill == 0) {
g_ScenarioData.koh.occupiedteam = -1;
g_ScenarioData.koh.elapsed240 = 0;
} else {
if (numteamsinhill == 1) {
// Set hillteam for later
for (hillteam = 0; hillteam < 8; hillteam++) {
if (teamsinhill[hillteam]) {
break;
}
}
} else {
// There are multiple teams in the hill.
// This code attempts to filter the teamsinhill array to only
// those which have the most chrs, but the teamsinhill array
// only contains values 0 or 1 so it effectively does nothing.
mostchrs = 0;
for (s0 = 0; s0 < 8; s0++) {
if (teamsinhill[s0] > mostchrs) {
mostchrs = teamsinhill[s0];
}
}
for (s0 = 0; s0 < 8; s0++) {
if (teamsinhill[s0] != mostchrs) {
teamsinhill[s0] = false;
}
}
// Count the number of teams who are tied for the most chrs in
// the hill. Or rather, because the teamsinhill array only
// contains 0 or 1 values, this is just recounting the number of
// teams who have presence in the hill.
for (s0 = 0; s0 < 8; s0++) {
if (teamsinhill[s0]) {
dualoccupancy++;
}
}
dualoccupancy = dualoccupancy >= 2 ? true : false;
// Set the hillteam to whoever was holding it previously
// so the hill remains the same colour
for (hillteam = 0; hillteam < 8; hillteam++) {
if (teamsinhill[hillteam] && hillteam == g_ScenarioData.koh.occupiedteam) {
break;
}
}
if (hillteam == 8) {
// This happens if the controlling team leaves the hill
// and there are two other teams still in the hill.
// The hill goes green until one team holds it exclusively.
g_ScenarioData.koh.occupiedteam = -1;
hillteam = -1;
}
}
// At this point we know there is a team in the hill on this frame.
// So if these don't match then the hill is turning into a team
// colour rather than going green.
if (hillteam != g_ScenarioData.koh.occupiedteam) {
sndStart(var80095200, SFX_MP_HILLENTERED, 0, -1, -1, -1, -1, -1);
g_ScenarioData.koh.occupiedteam = hillteam;
g_ScenarioData.koh.elapsed240 = 0;
// "%has captured the Hill!"
sprintf(text, langGet(L_MPWEAPONS_022), &g_BossFile.teamnames[hillteam]);
prevplayernum2 = g_Vars.currentplayernum;
for (playernum1 = 0; playernum1 < PLAYERCOUNT(); playernum1++) {
setCurrentPlayerNum(playernum1);
chr = g_Vars.currentplayer->prop->chr;
if (radarGetTeamIndex(chr->team) == g_ScenarioData.koh.occupiedteam) {
// "We have the Hill!"
hudmsgCreateWithFlags(langGet(L_MPWEAPONS_021), HUDMSGTYPE_MPSCENARIO, HUDMSGFLAG_ONLYIFALIVE);
} else {
hudmsgCreateWithFlags(text, HUDMSGTYPE_MPSCENARIO, HUDMSGFLAG_ONLYIFALIVE);
}
}
setCurrentPlayerNum(prevplayernum2);
} else {
// A team is remaining in the hill.
// Only tick the hill timer if they have exclusive occupancy.
if (!dualoccupancy) {
g_ScenarioData.koh.elapsed240 += g_Vars.lvupdate240;
if (g_ScenarioData.koh.elapsed240 >= g_Vars.mphilltime * PALDOWN(240) + PALDOWN(2400)) {
// Scored a point
sndStart(var80095200, SFX_MP_SCOREPOINT, 0, -1, -1, -1, -1, -1);
// @bug: There is no check for a chr being dead here.
// If a player dies in the hill and waits on the
// "press start" screen while their team mate scores the
// hill, the dead player will always be awarded a point.
for (playernum2 = 0; playernum2 < g_MpNumChrs; playernum2++) {
if (radarGetTeamIndex(g_MpAllChrPtrs[playernum2]->team) == g_ScenarioData.koh.occupiedteam) {
prop = g_MpAllChrPtrs[playernum2]->prop;
if (prop->rooms[0] == g_ScenarioData.koh.hillrooms[0]) {
g_MpAllChrConfigPtrs[playernum2]->numpoints++;
}
}
}
prevplayernum1 = g_Vars.currentplayernum;
for (playernum2 = 0; playernum2 < g_MpNumChrs; playernum2++) {
if (g_MpAllChrPtrs[playernum2]->aibot == NULL
&& radarGetTeamIndex(g_MpAllChrPtrs[playernum2]->team) == g_ScenarioData.koh.occupiedteam) {
setCurrentPlayerNum(playernum2);
// "King of the Hill!"
hudmsgCreateWithFlags(langGet(L_MPWEAPONS_020), HUDMSGTYPE_MPSCENARIO, HUDMSGFLAG_ONLYIFALIVE);
}
}
setCurrentPlayerNum(prevplayernum1);
g_ScenarioData.koh.occupiedteam = -1;
g_ScenarioData.koh.elapsed240 = 0;
if (g_MpSetup.options & MPOPTION_KOH_MOBILEHILL) {
g_ScenarioData.koh.movehill = true;
}
}
}
}
}
// Calculate what colour the hill should tween towards
if (g_ScenarioData.koh.occupiedteam == -1) {
targetr = 0.25f;
targetg = 1;
targetb = 0.25f;
} else {
u32 colour = g_TeamColours[g_ScenarioData.koh.occupiedteam];
targetr = ((s32)(colour >> 24 & 0xff) + 0xff) * (1.0f / 512.0f);
targetg = ((s32)(colour >> 16 & 0xff) + 0xff) * (1.0f / 512.0f);
targetb = ((s32)(colour >> 8 & 0xff) + 0xff) * (1.0f / 512.0f);
}
}
// Tween the colour components towards the target colour.
// @bug: This increments using g_Vars.diffframe60, which is updated while
// the game is paused. Because of this, if you pause as soon as a hill is
// scored then the colour fade and selection of the new hill will happen
// while paused.
if (g_ScenarioData.koh.colourfracr != targetr) {
for (i = 0; i < g_Vars.diffframe60; i++) {
#if PAL
g_ScenarioData.koh.colourfracr = 0.0597f * targetr + 0.9403f * g_ScenarioData.koh.colourfracr;
#else
g_ScenarioData.koh.colourfracr = 0.05f * targetr + 0.95f * g_ScenarioData.koh.colourfracr;
#endif
}
}
if (g_ScenarioData.koh.colourfracg != targetg) {
for (i = 0; i < g_Vars.diffframe60; i++) {
#if PAL
g_ScenarioData.koh.colourfracg = 0.0597f * targetg + 0.9403f * g_ScenarioData.koh.colourfracg;
#else
g_ScenarioData.koh.colourfracg = 0.05f * targetg + 0.95f * g_ScenarioData.koh.colourfracg;
#endif
}
}
if (g_ScenarioData.koh.colourfracb != targetb) {
for (i = 0; i < g_Vars.diffframe60; i++) {
#if PAL
g_ScenarioData.koh.colourfracb = 0.0597f * targetb + 0.9403f * g_ScenarioData.koh.colourfracb;
#else
g_ScenarioData.koh.colourfracb = 0.05f * targetb + 0.95f * g_ScenarioData.koh.colourfracb;
#endif
}
}
}
Gfx *kohRenderHud(Gfx *gdl)
{
s32 time240;
s32 mins;
s32 secs;
s32 textwidth;
s32 textheight;
s32 x;
s32 y;
struct chrdata *chr = g_Vars.currentplayer->prop->chr;
char text[64];
if (radarGetTeamIndex(chr->team) == g_ScenarioData.koh.occupiedteam && !g_ScenarioData.koh.movehill) {
x = viGetViewLeft() + viGetViewWidth() / 2;
y = viGetViewTop() + 10;
time240 = g_Vars.mphilltime * PALDOWN(240) - g_ScenarioData.koh.elapsed240;
time240 += PAL ? 2199 : 2400;
mins = time240 / PALDOWN(60 * 240);
time240 -= PALDOWN(60 * 240) * mins;
#if PAL
secs = time240 / PALDOWN(240);
#else
secs = (time240 + (PALDOWN(240) - 1)) / PALDOWN(240);
#endif
if ((g_Vars.mphilltime * 60 + 600) / 3600) {
sprintf(text, "%d:%02d", mins, secs);
} else {
sprintf(text, "%02d", secs);
}
gdl = func0f153628(gdl);
textMeasure(&textheight, &textwidth, text, g_CharsHandelGothicXs, g_FontHandelGothicXs, 0);
x -= textwidth / 2;
textwidth += x;
textheight += y;
#if VERSION >= VERSION_NTSC_1_0
gdl = func0f153990(gdl, x, y, textwidth, textheight);
gdl = textRender(gdl, &x, &y, text, g_CharsNumeric, g_FontNumeric, 0x00ff00a0, 0xa0, viGetWidth(), viGetHeight(), 0, 0);
#else
gdl = func0f153858(gdl, &x, &y, &textwidth, &textheight);
gdl = textRender(gdl, &x, &y, text, g_CharsNumeric, g_FontNumeric, 0x00ff00a0, 0x88, viGetWidth(), viGetHeight(), 0, 0);
#endif
gdl = func0f153780(gdl);
}
return gdl;
}
void kohCalculatePlayerScore(struct mpchrconfig *mpchr, s32 mpchrnum, s32 *score, s32 *deaths)
{
struct mpchrconfig *loopmpchr;
s32 i;
*score = 0;
*score += mpchr->numpoints;
if (g_MpSetup.options & MPOPTION_KILLSSCORE) {
for (i = 0; i != MAX_MPCHRS; i++) {
if (i == mpchrnum) {
*score -= mpchr->killcounts[i];
} else {
loopmpchr = MPCHR(i);
if (loopmpchr->team == mpchr->team) {
*score -= mpchr->killcounts[i];
} else {
*score += mpchr->killcounts[i];
}
}
}
}
*deaths = mpchr->numdeaths;
}
Gfx *kohRadarExtra(Gfx *gdl)
{
if (g_MpSetup.options & MPOPTION_KOH_HILLONRADAR && !g_ScenarioData.koh.movehill) {
struct coord dist;
u32 colour;
dist.x = g_ScenarioData.koh.hillpos.x - g_Vars.currentplayer->prop->pos.x;
dist.y = g_ScenarioData.koh.hillpos.y - g_Vars.currentplayer->prop->pos.y;
dist.z = g_ScenarioData.koh.hillpos.z - g_Vars.currentplayer->prop->pos.z;
if (g_ScenarioData.koh.occupiedteam == -1) {
colour = 0x00ff0000;
} else {
colour = g_TeamColours[g_ScenarioData.koh.occupiedteam];
}
gdl = radarDrawDot(gdl, NULL, &dist, colour, 0, 1);
}
return gdl;
}
void kohAddHill(s32 *cmd)
{
if (g_ScenarioData.koh.hillcount < ARRAYCOUNT(g_ScenarioData.koh.hillpads)) {
g_ScenarioData.koh.hillpads[g_ScenarioData.koh.hillcount] = cmd[1];
g_ScenarioData.koh.hillcount++;
}
}
bool kohIsRoomHighlighted(s16 room)
{
return room == g_ScenarioData.koh.hillrooms[0];
}
void kohHighlightRoom(s16 roomnum, s32 *arg1, s32 *arg2, s32 *arg3)
{
if (roomnum == g_ScenarioData.koh.hillrooms[0]) {
f32 a = *arg1;
f32 b = *arg2;
f32 c = *arg3;
a *= g_ScenarioData.koh.colourfracr;
b *= g_ScenarioData.koh.colourfracg;
c *= g_ScenarioData.koh.colourfracb;
*arg1 = a;
*arg2 = b;
*arg3 = c;
}
}

View File

@ -0,0 +1,307 @@
/**
* Pop a Cap
*
* At the start of the match, a single player is randomly chosen as the victim.
* Players must kill the victim in order to score, while the victim scores a
* point for every 60 seconds they remain alive. Once killed, another player is
* chosen as the victim.
*/
struct menuitem g_PacOptionsMenuItems[] = {
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_222, MPOPTION_ONEHITKILLS, menuhandlerMpOneHitKills }, // "One-Hit Kills"
{ MENUITEMTYPE_DROPDOWN, 0, 0x00020000, L_MPMENU_223, 0x00000000, menuhandlerMpSlowMotion }, // "Slow Motion"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_224, MPOPTION_FASTMOVEMENT, menuhandlerMpCheckboxOption }, // "Fast Movement"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_225, MPOPTION_DISPLAYTEAM, menuhandlerMpDisplayTeam }, // "Display Team"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_226, MPOPTION_NORADAR, menuhandlerMpCheckboxOption }, // "No Radar"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_227, MPOPTION_NOAUTOAIM, menuhandlerMpCheckboxOption }, // "No Auto-Aim"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_OPTIONS_493, MPOPTION_KILLSSCORE, menuhandlerMpCheckboxOption }, // "Kills Score"
{ MENUITEMTYPE_SEPARATOR, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_230, MPOPTION_PAC_HIGHLIGHTTARGET, menuhandlerMpCheckboxOption }, // "Highlight Target"
{ MENUITEMTYPE_CHECKBOX, 0, 0x00020000, L_MPMENU_238, MPOPTION_PAC_SHOWONRADAR, menuhandlerMpCheckboxOption }, // "Show on Radar"
{ MENUITEMTYPE_SEPARATOR, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
{ MENUITEMTYPE_SELECTABLE, 0, 0x00000008, L_MPMENU_239, 0x00000000, NULL }, // "Back"
{ MENUITEMTYPE_END, 0, 0x00000000, 0x00000000, 0x00000000, NULL },
};
struct menudialog g_PacOptionsMenuDialog = {
MENUDIALOGTYPE_DEFAULT,
L_MPMENU_218, // "Pop a Cap Options"
g_PacOptionsMenuItems,
mpOptionsMenuDialog,
0x00000010,
NULL,
};
void pacReset(void)
{
s32 i;
s32 j;
struct scenariodata_pac *data = &g_ScenarioData.pac;
data->victimindex = -1;
data->age240 = 0;
osSyncPrintf("PopACapReset -> num_mplayers=%d : Working\n", g_MpNumChrs);
for (i = 0; i != MAX_MPCHRS; i++) {
data->killcounts[i] = 0;
data->survivalcounts[i] = 0;
}
i = 0;
while (i < g_MpNumChrs) {
bool isnew;
s32 victimplayernum = random() % g_MpNumChrs;
for (j = 0, isnew = true; j < i; j++) {
if (data->victims[j] == victimplayernum) {
isnew = false;
break;
}
}
if (isnew) {
data->victims[i] = victimplayernum;
i++;
}
}
osSyncPrintf("PopACapReset -> Generated %d victims for this game : Listing\n", i);
for (j = 0; j < g_MpNumChrs; j++) {
osSyncPrintf("PopACapReset -> Victim %d is player %d\n", j, data->victims[j]);
}
osSyncPrintf("PopACapReset -> Done\n");
}
void pacInit(void)
{
pacReset();
}
void pacInitProps(void)
{
pacReset();
}
bool pacHighlightProp(struct prop *prop, s32 *colour)
{
struct scenariodata_pac *data = &g_ScenarioData.pac;
if (g_MpSetup.options & MPOPTION_PAC_HIGHLIGHTTARGET
&& (prop->type == PROPTYPE_PLAYER || prop->type == PROPTYPE_CHR)
&& data->victimindex != -1
&& prop->chr == g_MpAllChrPtrs[data->victims[data->victimindex]]) {
colour[0] = 0;
colour[1] = 0xff;
colour[2] = 0;
colour[3] = 0x40;
return true;
}
return false;
}
void pacApplyNextVictim(void)
{
struct scenariodata_pac *data = &g_ScenarioData.pac;
s32 vplayernum;
char text[64];
s32 i;
data->victimindex++;
if (data->victimindex == g_MpNumChrs) {
data->victimindex = 0;
}
data->age240 = 0;
vplayernum = data->victims[data->victimindex];
for (i = 0; i < PLAYERCOUNT(); i++) {
if (vplayernum == i) {
sprintf(text, langGet(L_MPWEAPONS_013)); // "You are the victim!"
} else if (scenarioChrsAreSameTeam(vplayernum, i)) {
sprintf(text, langGet(L_MPWEAPONS_014), g_MpAllChrConfigPtrs[vplayernum]->name); // "Protect %s!"
} else {
sprintf(text, langGet(L_MPWEAPONS_015), g_MpAllChrConfigPtrs[vplayernum]->name); // "Get %s!"
}
scenarioCreateHudmsg(i, text);
}
}
void pacHandleDeath(s32 aplayernum, s32 vplayernum)
{
struct scenariodata_pac *data = &g_ScenarioData.pac;
if (data->victimindex >= 0 && vplayernum == data->victims[data->victimindex]) {
if (aplayernum != vplayernum) {
if (aplayernum >= 0) {
if (scenarioChrsAreSameTeam(aplayernum, vplayernum)) {
scenarioCreateHudmsg(aplayernum, langGet(L_MPWEAPONS_008)); // "You're supposed to look"
scenarioCreateHudmsg(aplayernum, langGet(L_MPWEAPONS_009)); // "after your friends!"
} else {
data->killcounts[aplayernum]++;
scenarioCreateHudmsg(aplayernum, langGet(L_MPWEAPONS_010)); // "Well done!"
scenarioCreateHudmsg(aplayernum, langGet(L_MPWEAPONS_011)); // "You popped a cap!"
scenarioCreateHudmsg(aplayernum, langGet(L_MPWEAPONS_012)); // "Have 2 Points..."
}
}
pacApplyNextVictim();
} else {
#if VERSION >= VERSION_NTSC_1_0
data->age240 = 0;
#endif
}
}
}
void pacTick(void)
{
struct scenariodata_pac *data = &g_ScenarioData.pac;
if (data->victimindex == -1) {
pacApplyNextVictim();
osSyncPrintf("PopACapTick : Current Victim = %d (Player %d)\n",
data->victimindex, data->victims[data->victimindex]);
}
if (data->victimindex >= 0) {
#if VERSION >= VERSION_NTSC_1_0
if (data->victims[data->victimindex] >= PLAYERCOUNT() ||
g_Vars.players[data->victims[data->victimindex]]->isdead == false)
#endif
{
data->age240 += g_Vars.lvupdate240;
if (data->age240 > (u32)PALDOWN(240 * 60)) {
data->age240 = 0;
data->survivalcounts[data->victims[data->victimindex]]++;
scenarioCreateHudmsg(data->victims[data->victimindex], langGet(L_MPWEAPONS_007)); // "Have a point for living!"
}
}
}
}
Gfx *pacRenderHud(Gfx *gdl)
{
struct scenariodata_pac *data = &g_ScenarioData.pac;
s32 time240;
s32 mins;
s32 secs;
s32 textwidth;
s32 textheight;
s32 x;
s32 y;
char text[64];
#if VERSION >= VERSION_NTSC_1_0
if (g_Vars.currentplayernum == data->victims[data->victimindex] && !g_Vars.currentplayer->isdead)
#else
if (g_Vars.currentplayernum == data->victims[data->victimindex])
#endif
{
time240 = PALDOWN(60 * 240) - data->age240;
x = viGetViewLeft() + viGetViewWidth() / 2;
y = viGetViewTop() + 10;
if (time240 < 0) {
time240 = 0;
}
mins = time240 / PALDOWN(60 * 240);
time240 -= PALDOWN(60 * 240) * mins;
secs = (time240 + (PALDOWN(240) - 1)) / PALDOWN(240);
sprintf(text, "%d:%02d", mins, secs);
gdl = func0f153628(gdl);
textMeasure(&textheight, &textwidth, text, g_CharsHandelGothicXs, g_FontHandelGothicXs, 0);
x -= textwidth / 2;
textwidth += x;
textheight += y;
#if VERSION >= VERSION_NTSC_1_0
gdl = func0f153990(gdl, x, y, textwidth, textheight);
gdl = textRender(gdl, &x, &y, text, g_CharsNumeric, g_FontNumeric, 0x00ff00a0, 0xa0, viGetWidth(), viGetHeight(), 0, 0);
#else
gdl = func0f153858(gdl, &x, &y, &textwidth, &textheight);
gdl = textRender(gdl, &x, &y, text, g_CharsNumeric, g_FontNumeric, 0x00ff00a0, 0x88, viGetWidth(), viGetHeight(), 0, 0);
#endif
gdl = func0f153780(gdl);
}
return gdl;
}
void pacCalculatePlayerScore(struct mpchrconfig *mpchr, s32 mpchrnum, s32 *score, s32 *arg3)
{
struct mpchrconfig *loopmpchr;
s32 i;
s32 index;
*score = 0;
index = func0f18d0e8(mpchrnum);
if (index >= 0) {
*score += g_ScenarioData.pac.killcounts[index] * 2;
*score += g_ScenarioData.pac.survivalcounts[index];
}
if (g_MpSetup.options & MPOPTION_KILLSSCORE) {
for (i = 0; i != MAX_MPCHRS; i++) {
if (i == mpchrnum) {
*score -= mpchr->killcounts[i];
} else if (g_MpSetup.options & MPOPTION_TEAMSENABLED) {
loopmpchr = MPCHR(i);
if (loopmpchr->team == mpchr->team) {
*score -= mpchr->killcounts[i];
} else {
*score += mpchr->killcounts[i];
}
} else {
*score += mpchr->killcounts[i];
}
}
}
*arg3 = mpchr->numdeaths;
}
Gfx *pacRadarExtra(Gfx *gdl)
{
return gdl;
}
bool pacRadarChr(Gfx **gdl, struct prop *prop)
{
struct scenariodata_pac *data = &g_ScenarioData.pac;
struct coord dist;
if ((g_MpSetup.options & MPOPTION_PAC_SHOWONRADAR) && data->victimindex >= 0) {
struct prop *vprop = g_MpAllChrPtrs[data->victims[data->victimindex]]->prop;
if (vprop == prop) {
dist.x = prop->pos.x - g_Vars.currentplayer->prop->pos.x;
dist.y = prop->pos.y - g_Vars.currentplayer->prop->pos.y;
dist.z = prop->pos.z - g_Vars.currentplayer->prop->pos.z;
if (g_MpSetup.options & MPOPTION_TEAMSENABLED) {
u32 colour = g_TeamColours[radarGetTeamIndex(prop->chr->team)];
*gdl = radarDrawDot(*gdl, vprop, &dist, colour, 0, 1);
} else {
*gdl = radarDrawDot(*gdl, vprop, &dist, 0x00ff0000, 0, 1);
}
return true;
}
}
return false;
}

View File

@ -6219,13 +6219,7 @@ s32 menuhandlerMpMaximumTeams(s32 operation, struct menuitem *item, union handle
for (i = 0; i != MAX_MPCHRS; i++) {
if (g_MpSetup.chrslots & (1 << i)) {
struct mpchrconfig *mpchr;
if (i < 4) {
mpchr = &g_PlayerConfigsArray[i].base;
} else {
mpchr = &g_BotConfigsArray[i - 4].base;
}
struct mpchrconfig *mpchr = MPCHR(i);
mpchr->team = team++;
@ -6248,13 +6242,7 @@ s32 menuhandlerMpHumansVsSimulants(s32 operation, struct menuitem *item, union h
for (i = 0; i != MAX_MPCHRS; i++) {
if (g_MpSetup.chrslots & (1 << i)) {
struct mpchrconfig *mpchr;
if (i < 4) {
mpchr = &g_PlayerConfigsArray[i].base;
} else {
mpchr = &g_BotConfigsArray[i - 4].base;
}
struct mpchrconfig *mpchr = MPCHR(i);
mpchr->team = i < 4 ? 0 : 1;
}
@ -6276,13 +6264,7 @@ s32 menuhandlerMpHumanSimulantPairs(s32 operation, struct menuitem *item, union
for (i = 0; i != MAX_MPCHRS; i++) {
if (g_MpSetup.chrslots & (1 << i)) {
struct mpchrconfig *mpchr;
if (i < 4) {
mpchr = &g_PlayerConfigsArray[i].base;
} else {
mpchr = &g_BotConfigsArray[i - 4].base;
}
struct mpchrconfig *mpchr = MPCHR(i);
if (i < 4) {
mpchr->team = team_ids[playerindex++];
@ -8427,17 +8409,17 @@ glabel func0f17fa28
/* f17fa68: 3c148008 */ lui $s4,%hi(g_MpChangeSimulantMenuDialog)
/* f17fa6c: 3c158008 */ lui $s5,%hi(g_MpEditSimulantMenuDialog)
/* f17fa70: 3c168008 */ lui $s6,%hi(g_MpCombatOptionsMenuDialog)
/* f17fa74: 3c178008 */ lui $s7,%hi(g_MpBriefcaseOptionsMenuDialog)
/* f17fa78: 3c1e8008 */ lui $s8,%hi(g_MpCaptureOptionsMenuDialog)
/* f17fa7c: 3c098008 */ lui $t1,%hi(g_MpPopacapOptionsMenuDialog)
/* f17fa80: 3c088008 */ lui $t0,%hi(g_MpHackerOptionsMenuDialog)
/* f17fa84: 3c078008 */ lui $a3,%hi(g_MpHillOptionsMenuDialog)
/* f17fa74: 3c178008 */ lui $s7,%hi(g_HtbOptionsMenuDialog)
/* f17fa78: 3c1e8008 */ lui $s8,%hi(g_CtcOptionsMenuDialog)
/* f17fa7c: 3c098008 */ lui $t1,%hi(g_PacOptionsMenuDialog)
/* f17fa80: 3c088008 */ lui $t0,%hi(g_HtmOptionsMenuDialog)
/* f17fa84: 3c078008 */ lui $a3,%hi(g_KohOptionsMenuDialog)
/* f17fa88: afb00018 */ sw $s0,0x18($sp)
/* f17fa8c: 24e76ce0 */ addiu $a3,$a3,%lo(g_MpHillOptionsMenuDialog)
/* f17fa90: 25086dfc */ addiu $t0,$t0,%lo(g_MpHackerOptionsMenuDialog)
/* f17fa94: 25296f80 */ addiu $t1,$t1,%lo(g_MpPopacapOptionsMenuDialog)
/* f17fa98: 27de6b48 */ addiu $s8,$s8,%lo(g_MpCaptureOptionsMenuDialog)
/* f17fa9c: 26f769d4 */ addiu $s7,$s7,%lo(g_MpBriefcaseOptionsMenuDialog)
/* f17fa8c: 24e76ce0 */ addiu $a3,$a3,%lo(g_KohOptionsMenuDialog)
/* f17fa90: 25086dfc */ addiu $t0,$t0,%lo(g_HtmOptionsMenuDialog)
/* f17fa94: 25296f80 */ addiu $t1,$t1,%lo(g_PacOptionsMenuDialog)
/* f17fa98: 27de6b48 */ addiu $s8,$s8,%lo(g_CtcOptionsMenuDialog)
/* f17fa9c: 26f769d4 */ addiu $s7,$s7,%lo(g_HtbOptionsMenuDialog)
/* f17faa0: 26d668b8 */ addiu $s6,$s6,%lo(g_MpCombatOptionsMenuDialog)
/* f17faa4: 26b5592c */ addiu $s5,$s5,%lo(g_MpEditSimulantMenuDialog)
/* f17faa8: 26945834 */ addiu $s4,$s4,%lo(g_MpChangeSimulantMenuDialog)
@ -8558,14 +8540,14 @@ glabel func0f17fa28
/* f17fc30: 00000000 */ nop
/* f17fc34: 0fc3cdb7 */ jal menuPopDialog
/* f17fc38: 00000000 */ nop
/* f17fc3c: 3c078008 */ lui $a3,%hi(g_MpHillOptionsMenuDialog)
/* f17fc40: 3c088008 */ lui $t0,%hi(g_MpHackerOptionsMenuDialog)
/* f17fc44: 3c098008 */ lui $t1,%hi(g_MpPopacapOptionsMenuDialog)
/* f17fc3c: 3c078008 */ lui $a3,%hi(g_KohOptionsMenuDialog)
/* f17fc40: 3c088008 */ lui $t0,%hi(g_HtmOptionsMenuDialog)
/* f17fc44: 3c098008 */ lui $t1,%hi(g_PacOptionsMenuDialog)
/* f17fc48: 3c1f8007 */ lui $ra,%hi(g_MpPlayerNum)
/* f17fc4c: 27ff1448 */ addiu $ra,$ra,%lo(g_MpPlayerNum)
/* f17fc50: 25296f80 */ addiu $t1,$t1,%lo(g_MpPopacapOptionsMenuDialog)
/* f17fc54: 25086dfc */ addiu $t0,$t0,%lo(g_MpHackerOptionsMenuDialog)
/* f17fc58: 24e76ce0 */ addiu $a3,$a3,%lo(g_MpHillOptionsMenuDialog)
/* f17fc50: 25296f80 */ addiu $t1,$t1,%lo(g_PacOptionsMenuDialog)
/* f17fc54: 25086dfc */ addiu $t0,$t0,%lo(g_HtmOptionsMenuDialog)
/* f17fc58: 24e76ce0 */ addiu $a3,$a3,%lo(g_KohOptionsMenuDialog)
.L0f17fc5c:
/* f17fc5c: 5200ffa7 */ beqzl $s0,.L0f17fafc
/* f17fc60: 8fe20000 */ lw $v0,0x0($ra)

View File

@ -178,11 +178,7 @@ void mpstatsRecordPlayerSuicide(void)
time = getMissionTime();
mpindex = g_Vars.currentplayerstats->mpindex;
if (mpindex < 4) {
mpchr = &g_PlayerConfigsArray[mpindex].base;
} else {
mpchr = &g_BotConfigsArray[mpindex - 4].base;
}
mpchr = MPCHR(mpindex);
// Show HUD message
// "Suicide count: %d"
@ -238,7 +234,7 @@ void mpstatsRecordDeath(s32 aplayernum, s32 vplayernum)
char text[256];
if (g_Vars.normmplayerisrunning && g_MpSetup.scenario == MPSCENARIO_POPACAP) {
scenarioPacHandleDeath(aplayernum, vplayernum);
pacHandleDeath(aplayernum, vplayernum);
}
// Find attacker and victim mpchrs
@ -246,11 +242,7 @@ void mpstatsRecordDeath(s32 aplayernum, s32 vplayernum)
ampindex = func0f18d074(aplayernum);
if (ampindex >= 0) {
if (ampindex < 4) {
ampchr = &g_PlayerConfigsArray[ampindex].base;
} else {
ampchr = &g_BotConfigsArray[ampindex - 4].base;
}
ampchr = MPCHR(ampindex);
}
}
@ -258,11 +250,7 @@ void mpstatsRecordDeath(s32 aplayernum, s32 vplayernum)
vmpindex = func0f18d074(vplayernum);
if (vmpindex >= 0) {
if (vmpindex < 4) {
vmpchr = &g_PlayerConfigsArray[vmpindex].base;
} else {
vmpchr = &g_BotConfigsArray[vmpindex - 4].base;
}
vmpchr = MPCHR(vmpindex);
}
}

View File

@ -3340,7 +3340,7 @@ glabel var7f1aa1d8
/* f0692ac: 27a70050 */ addiu $a3,$sp,0x50
/* f0692b0: 460a8481 */ sub.s $f18,$f16,$f10
/* f0692b4: e7b2005c */ swc1 $f18,0x5c($sp)
/* f0692b8: 0fc6192e */ jal scenarioCallback38
/* f0692b8: 0fc6192e */ jal scenarioHighlightRoom
/* f0692bc: 85c40028 */ lh $a0,0x28($t6)
/* f0692c0: 920f0000 */ lbu $t7,0x0($s0)
/* f0692c4: 8fb80058 */ lw $t8,0x58($sp)
@ -3684,7 +3684,7 @@ glabel var7f1aa1d8
/* f068518: 27a70050 */ addiu $a3,$sp,0x50
/* f06851c: 460a8481 */ sub.s $f18,$f16,$f10
/* f068520: e7b2005c */ swc1 $f18,0x5c($sp)
/* f068524: 0fc60248 */ jal scenarioCallback38
/* f068524: 0fc60248 */ jal scenarioHighlightRoom
/* f068528: 85c40028 */ lh $a0,0x28($t6)
/* f06852c: 920f0000 */ lbu $t7,0x0($s0)
/* f068530: 8fb80058 */ lw $t8,0x58($sp)
@ -52709,7 +52709,7 @@ glabel var7f1aa82c
/* f0818b0: 8cca0318 */ lw $t2,0x318($a2)
/* f0818b4: 51400006 */ beqzl $t2,.L0f0818d0
/* f0818b8: 8cc20284 */ lw $v0,0x284($a2)
/* f0818bc: 0fc61788 */ jal scenarioHighlight
/* f0818bc: 0fc61788 */ jal scenarioHighlightProp
/* f0818c0: 8fa400f8 */ lw $a0,0xf8($sp)
/* f0818c4: 3c06800a */ lui $a2,%hi(g_Vars)
/* f0818c8: 24c69fc0 */ addiu $a2,$a2,%lo(g_Vars)
@ -53344,7 +53344,7 @@ glabel var7f1aa82c
/* f0818b0: 8cca0318 */ lw $t2,0x318($a2)
/* f0818b4: 51400006 */ beqzl $t2,.L0f0818d0
/* f0818b8: 8cc20284 */ lw $v0,0x284($a2)
/* f0818bc: 0fc61788 */ jal scenarioHighlight
/* f0818bc: 0fc61788 */ jal scenarioHighlightProp
/* f0818c0: 8fa400f8 */ lw $a0,0xf8($sp)
/* f0818c4: 3c06800a */ lui $a2,%hi(g_Vars)
/* f0818c8: 24c69fc0 */ addiu $a2,$a2,%lo(g_Vars)
@ -53755,7 +53755,7 @@ glabel var7f1aa82c
// }
//
// if (g_Vars.normmplayerisrunning) {
// scenarioHighlight(prop, colour);
// scenarioHighlightProp(prop, colour);
// }
//
// if (g_Vars.currentplayer->visionmode == VISIONMODE_XRAY) {
@ -61018,7 +61018,7 @@ bool propobjInteract(struct prop *prop)
}
if (g_Vars.normmplayerisrunning) {
scenarioHtmActivateUplink(g_Vars.currentplayer->prop->chr, prop);
scenarioHandleActivatedProp(g_Vars.currentplayer->prop->chr, prop);
} else {
if (g_Vars.currentplayernum == g_Vars.coopplayernum) {
obj->hidden |= OBJHFLAG_ACTIVATED_BY_COOP;
@ -62731,7 +62731,7 @@ glabel var7f1aae70
/* f088a94: 8d0f04cc */ lw $t7,0x4cc($t0)
/* f088a98: 8c4c00bc */ lw $t4,0xbc($v0)
/* f088a9c: 8fa500a0 */ lw $a1,0xa0($sp)
/* f088aa0: 0fc61d04 */ jal chrGiveUplink
/* f088aa0: 0fc61d04 */ jal scenarioPickUpUplink
/* f088aa4: 8d840004 */ lw $a0,0x4($t4)
/* f088aa8: 10400006 */ beqz $v0,.L0f088ac4
/* f088aac: 00401825 */ or $v1,$v0,$zero
@ -63378,7 +63378,7 @@ glabel var7f1aae70
/* f088a94: 8d0f04cc */ lw $t7,0x4cc($t0)
/* f088a98: 8c4c00bc */ lw $t4,0xbc($v0)
/* f088a9c: 8fa500a0 */ lw $a1,0xa0($sp)
/* f088aa0: 0fc61d04 */ jal chrGiveUplink
/* f088aa0: 0fc61d04 */ jal scenarioPickUpUplink
/* f088aa4: 8d840004 */ lw $a0,0x4($t4)
/* f088aa8: 10400006 */ beqz $v0,.L0f088ac4
/* f088aac: 00401825 */ or $v1,$v0,$zero
@ -64025,7 +64025,7 @@ glabel var7f1aae70
/* f088a94: 8d0f04cc */ lw $t7,0x4cc($t0)
/* f088a98: 8c4c00bc */ lw $t4,0xbc($v0)
/* f088a9c: 8fa500a0 */ lw $a1,0xa0($sp)
/* f088aa0: 0fc61d04 */ jal chrGiveUplink
/* f088aa0: 0fc61d04 */ jal scenarioPickUpUplink
/* f088aa4: 8d840004 */ lw $a0,0x4($t4)
/* f088aa8: 10400006 */ beqz $v0,.L0f088ac4
/* f088aac: 00401825 */ or $v1,$v0,$zero
@ -64500,7 +64500,7 @@ glabel var7f1aae70
// }
//
// if (weapon->weaponnum == WEAPON_DATAUPLINK) {
// result = chrGiveUplink(g_Vars.currentplayer->prop->chr, prop);
// result = scenarioPickUpUplink(g_Vars.currentplayer->prop->chr, prop);
//
// if (result) {
// weaponPlayPickupSound(weapon->weaponnum);
@ -69892,7 +69892,7 @@ void weaponCreateForPlayerDrop(s32 weaponnum)
objDrop(prop, true);
if (weaponnum == WEAPON_BRIEFCASE2) {
scenarioReleaseToken(chr, prop);
scenarioHandleDroppedToken(chr, prop);
}
}
}

View File

@ -331,7 +331,7 @@ Gfx *radarRender(Gfx *gdl)
if (i != playernum) {
if (g_Vars.players[i]->isdead == false
&& (g_Vars.players[i]->prop->chr->hidden & CHRHFLAG_CLOAKED) == 0
&& scenarioRadar2(&gdl, g_Vars.players[i]->prop) == false) {
&& scenarioRadarChr(&gdl, g_Vars.players[i]->prop) == false) {
pos.x = g_Vars.players[i]->prop->pos.x - g_Vars.currentplayer->prop->pos.x;
pos.y = g_Vars.players[i]->prop->pos.y - g_Vars.currentplayer->prop->pos.y;
pos.z = g_Vars.players[i]->prop->pos.z - g_Vars.currentplayer->prop->pos.z;
@ -372,7 +372,7 @@ Gfx *radarRender(Gfx *gdl)
for (i = 0; i < g_BotCount; i++) {
if (!chrIsDead(g_MpBotChrPtrs[i])
&& (g_MpBotChrPtrs[i]->hidden & CHRHFLAG_CLOAKED) == 0
&& scenarioRadar2(&gdl, g_MpBotChrPtrs[i]->prop) == false) {
&& scenarioRadarChr(&gdl, g_MpBotChrPtrs[i]->prop) == false) {
pos.x = g_MpBotChrPtrs[i]->prop->pos.x - g_Vars.currentplayer->prop->pos.x;
pos.y = g_MpBotChrPtrs[i]->prop->pos.y - g_Vars.currentplayer->prop->pos.y;
pos.z = g_MpBotChrPtrs[i]->prop->pos.z - g_Vars.currentplayer->prop->pos.z;
@ -388,7 +388,7 @@ Gfx *radarRender(Gfx *gdl)
}
}
gdl = scenarioRadar(gdl);
gdl = scenarioRadarExtra(gdl);
// Draw dots for r-tracked props
if (g_Vars.currentplayer->devicesactive & ~g_Vars.currentplayer->devicesinhibit & DEVICE_RTRACKER) {
@ -396,7 +396,7 @@ Gfx *radarRender(Gfx *gdl)
}
// Draw dot for the current player
if (scenarioRadar2(&gdl, g_Vars.currentplayer->prop) == 0) {
if (scenarioRadarChr(&gdl, g_Vars.currentplayer->prop) == false) {
pos.x = 0;
pos.y = 0;
pos.z = 0;

View File

@ -489,12 +489,11 @@ extern struct menudialog g_MpQuickTeamGameSetupMenuDialog;
extern struct menudialog g_MpQuickTeamMenuDialog;
extern struct menudialog g_CombatSimulatorMenuDialog;
extern struct menudialog g_MpCombatOptionsMenuDialog;
extern struct menudialog g_MpBriefcaseOptionsMenuDialog;
extern struct menudialog g_MpCaptureOptionsMenuDialog;
extern struct menudialog g_MpHillOptionsMenuDialog;
extern struct menudialog g_MpHackerOptionsMenuDialog;
extern struct menudialog g_MpPopacapOptionsMenuDialog;
extern struct mpscenariooverview g_MpScenarioOverviews[];
extern struct menudialog g_HtbOptionsMenuDialog;
extern struct menudialog g_CtcOptionsMenuDialog;
extern struct menudialog g_KohOptionsMenuDialog;
extern struct menudialog g_HtmOptionsMenuDialog;
extern struct menudialog g_PacOptionsMenuDialog;
extern struct menudialog g_MpScenarioMenuDialog;
extern struct menudialog g_MpQuickTeamScenarioMenuDialog;
extern s32 var80087260;

View File

@ -7,55 +7,27 @@
extern struct menudialog g_MpScenarioMenuDialog;
extern struct menudialog g_MpQuickTeamScenarioMenuDialog;
void scenarioHtbInit(void);
s32 scenarioHtbCallback08(void);
void scenarioHtbReset(void);
void scenarioHtbTick(void);
void scenarioHtbCallback14(struct chrdata *chr);
void scenarioHtbCalculatePlayerScore(struct mpchrconfig *mpchr, s32 mpchrnum, s32 *score, s32 *deaths);
Gfx *scenarioHtbRadar(Gfx *gdl);
bool scenarioHtbRadar2(Gfx **gdl, struct prop *prop);
bool scenarioHtbHighlight(struct prop *prop, s32 *colour);
void scenarioCtcInit(void);
s32 scenarioCtcCallback08(void);
void scenarioCtcTick(void);
void scenarioCtcCallback14(struct chrdata *chr);
void scenarioCtcCalculatePlayerScore(struct mpchrconfig *mpchr, s32 mpchrnum, s32 *score, s32 *deaths);
Gfx *scenarioCtcRadar(Gfx *gdl);
bool scenarioCtcRadar2(Gfx **gdl, struct prop *prop);
bool scenarioCtcChooseSpawnLocation(f32 arg0, struct coord *pos, s16 *rooms, struct prop *prop, f32 *arg4);
s32 scenarioCtcGetMaxTeams(void);
bool scenarioCtcIsRoomHighlighted(s16 room);
s32 menuhandlerMpHillTime(s32 operation, struct menuitem *item, union handlerdata *data);
void scenarioKohReadSave(struct savebuffer *buffer);
void scenarioKohWriteSave(struct savebuffer *buffer);
void scenarioKohInit(void);
void scenarioKohReset(void);
void scenarioKohCalculatePlayerScore(struct mpchrconfig *mpchr, s32 mpchrnum, s32 *score, s32 *deaths);
Gfx *scenarioKohRadar(Gfx *gdl);
bool scenarioKohIsRoomHighlighted(s16 arg0);
void scenarioHtmInit(void);
s32 scenarioHtmCallback08(void);
void scenarioHtmTick(void);
void scenarioHtmCalculatePlayerScore(struct mpchrconfig *mpchr, s32 mpchrnum, s32 *score, s32 *deaths);
bool scenarioHtmRadar2(Gfx **gdl, struct prop *prop);
bool scenarioHtmHighlight(struct prop *prop, s32 *colour);
void scenarioPacInit(void);
void scenarioPacReset(void);
void scenarioPacCalculatePlayerScore(struct mpchrconfig *mpchr, s32 mpchrnum, s32 *score, s32 *deaths);
Gfx *scenarioPacRadar(Gfx *gdl);
struct mpscenariooverview {
u16 name;
u16 shortname;
u8 requirefeature;
u8 teamonly;
};
extern struct mpscenariooverview g_MpScenarioOverviews[6];
s32 menuhandlerMpOpenOptions(s32 operation, struct menuitem *item, union handlerdata *data);
void scenarioReadSave(struct savebuffer *buffer);
void scenarioWriteSave(struct savebuffer *buffer);
void scenarioInit(void);
s32 scenarioCallback08(void);
void scenarioReset(void);
s32 scenarioNumProps(void);
void scenarioInitProps(void);
void scenarioTick(void);
void scenarioCallback14(struct chrdata *chr);
Gfx *scenarioRadar(Gfx *gdl);
bool scenarioRadar2(Gfx **gdl, struct prop *prop);
void scenarioTickChr(struct chrdata *chr);
Gfx *scenarioRadarExtra(Gfx *gdl);
bool scenarioRadarChr(Gfx **gdl, struct prop *prop);
f32 scenarioChooseSpawnLocation(f32 arg0, struct coord *pos, s16 *rooms, struct prop *prop);
s32 scenarioGetMaxTeams(void);
void scenarioCallback38(s16 arg0, s32 *arg1, s32 *arg2, s32 *arg3);
void scenarioHighlightRoom(s16 room, s32 *arg1, s32 *arg2, s32 *arg3);
#endif

View File

@ -73,49 +73,49 @@ s32 mpQuickTeamSimulantDifficultyHandler(s32 operation, struct menuitem *item, u
u32 func0f17fa28(void);
void func0f17fcb0(s32 silent);
s32 menuhandlerMpSlowMotion(s32 operation, struct menuitem *item, union handlerdata *data);
void mpHtbAddPad(s16 padnum);
void scenarioHtmRemoveAmmoCrateAtPad(s16 padnum);
void func0f180078(void);
void scenarioHtbCreateToken(void);
Gfx *scenarioHtbRenderHud(Gfx *gdl);
void scenarioCtcReset(void);
bool scenarioCtcHighlight(struct prop *prop, s32 *colour);
void mpCtcAddPad(s32 *cmd);
void scenarioCtcCallback38(s16 roomnum, s32 *arg1, s32 *arg2, s32 *arg3);
void scenarioKohTick(void);
Gfx *scenarioKohRenderHud(Gfx *gdl);
void mpKohAddHill(s32 *cmd);
void scenarioKohCallback38(s16 roomnum, s32 *arg1, s32 *arg2, s32 *arg3);
void mpHtmAddPad(s16 padnum);
void func0f182bf4(void);
void scenarioHtmCreateUplink(void);
void scenarioHtmReset(void);
void scenarioHtmCallback14(struct chrdata *chr);
Gfx *scenarioHtmRenderHud(Gfx *gdl);
Gfx *scenarioHtmRadar(Gfx *gdl);
void scenarioPacChooseVictims(void);
bool scenarioPacHighlight(struct prop *prop, s32 *colour);
void scenarioPacApplyNextVictim(void);
void scenarioPacHandleDeath(s32 cplayernum, s32 vplayernum);
void scenarioPacTick(void);
Gfx *scenarioPacRenderHud(Gfx *gdl);
bool scenarioPacRadar2(Gfx **gdl, struct prop *prop);
void htbAddPad(s16 padnum);
void htbRemoveAmmoCrateAtPad(s16 padnum);
void htbReset(void);
void htbCreateToken(void);
Gfx *htbRenderHud(Gfx *gdl);
void ctcInitProps(void);
bool ctcHighlightProp(struct prop *prop, s32 *colour);
void ctcAddPad(s32 *cmd);
void ctcHighlightRoom(s16 roomnum, s32 *arg1, s32 *arg2, s32 *arg3);
void kohTick(void);
Gfx *kohRenderHud(Gfx *gdl);
void kohAddHill(s32 *cmd);
void kohHighlightRoom(s16 roomnum, s32 *arg1, s32 *arg2, s32 *arg3);
void htmAddPad(s16 padnum);
void htmReset(void);
void htbCreateUplink(void);
void htmInitProps(void);
void htmTickChr(struct chrdata *chr);
Gfx *htmRenderHud(Gfx *gdl);
Gfx *htmRadarExtra(Gfx *gdl);
void pacReset(void);
bool pacHighlightProp(struct prop *prop, s32 *colour);
void pacApplyNextVictim(void);
void pacHandleDeath(s32 cplayernum, s32 vplayernum);
void pacTick(void);
Gfx *pacRenderHud(Gfx *gdl);
bool pacRadarChr(Gfx **gdl, struct prop *prop);
s32 mpOptionsMenuDialog(s32 operation, struct menudialog *dialog, union handlerdata *data);
char *mpMenuTextScenarioShortName(struct menuitem *item);
char *mpMenuTextScenarioName(struct menuitem *item);
s32 scenarioScenarioMenuHandler(s32 operation, struct menuitem *item, union handlerdata *data);
void mpCreateMatchStartHudmsgs(void);
void scenarioCreateMatchStartHudmsgs(void);
Gfx *scenarioRenderHud(Gfx *gdl);
void scenarioCalculatePlayerScore(struct mpchrconfig *mpchr, s32 chrnum, s32 *arg2, s32 *arg3);
bool scenarioHighlight(struct prop *prop, s32 *colour);
void mpPrepareScenario(void);
bool scenarioHighlightProp(struct prop *prop, s32 *colour);
void scenarioReset(void);
struct prop *scenarioCreateObj(s32 modelnum, s16 padnum, f32 arg2, u32 flags, u32 flags2, u32 flags3);
void mpCreateScenarioHudmsg(s32 playernum, char *message);
bool mpChrsAreSameTeam(s32 arg0, s32 arg1);
void scenarioCreateHudmsg(s32 playernum, char *message);
bool scenarioChrsAreSameTeam(s32 playernum1, s32 playernum2);
s32 scenarioPickUpBriefcase(struct chrdata *chr, struct prop *prop);
void scenarioReleaseToken(struct chrdata *chr, struct prop *prop);
s32 chrGiveUplink(struct chrdata *chr, struct prop *prop);
void scenarioHtmActivateUplink(struct chrdata *chr, struct prop *prop);
void scenarioHandleDroppedToken(struct chrdata *chr, struct prop *prop);
s32 scenarioPickUpUplink(struct chrdata *chr, struct prop *prop);
void scenarioHandleActivatedProp(struct chrdata *chr, struct prop *prop);
s32 menuhandlerMpDropOut(s32 operation, struct menuitem *item, union handlerdata *data);
s32 menuhandlerMpTeamsLabel(s32 operation, struct menuitem *item, union handlerdata *data);
s32 mpGetNumStages(void);

View File

@ -4673,34 +4673,6 @@ struct savebuffer {
u8 bytes[220];
};
struct mpscenario {
struct menudialog *optionsdialog;
void (*initfunc)(void);
s32 (*unk08)(void);
void (*resetfunc)(void);
void (*tickfunc)(void);
void (*unk14)(struct chrdata *chr);
Gfx *(*hudfunc)(Gfx *gdl);
void (*calcscorefunc)(struct mpchrconfig *mpchr, s32 chrnum, s32 *score, s32 *deaths);
Gfx *(*radarfunc)(Gfx *gdl);
bool (*radar2func)(Gfx **gdl, struct prop *prop);
bool (*highlightfunc)(struct prop *prop, s32 *colour);
bool (*spawnfunc)(f32 arg0, struct coord *pos, s16 *rooms, struct prop *prop, f32 *arg4);
s32 (*maxteamsfunc)(void);
bool (*isroomhighlightedfunc)(s16 room);
void (*unk38)(s16 arg0, s32 *arg1, s32 *arg2, s32 *arg3);
void *unk3c;
void (*readsavefunc)(struct savebuffer *buffer);
void (*writesavefunc)(struct savebuffer *buffer);
};
struct mpscenariooverview {
u16 name;
u16 shortname;
u8 requirefeature;
u8 teamonly;
};
struct mparena {
s16 stagenum;
u8 requirefeature;
@ -4768,8 +4740,8 @@ struct htmterminal {
};
struct scenariodata_htm {
/*0x800ac110*/ s16 nextindex;
/*0x800ac112*/ s16 unk002;
/*0x800ac110*/ s16 numpads;
/*0x800ac112*/ s16 numterminals;
/*0x800ac114*/ s16 padnums[60];
/*0x800ac18c*/ struct htmterminal terminals[7]; // only the first element is used
/*0x800ac1e0*/ s16 dlplayernum;
@ -4780,6 +4752,7 @@ struct scenariodata_htm {
/*0x800ac248*/ u32 unk138;
/*0x800ac24c*/ struct prop *uplink;
/*0x800ac250*/ u32 unk140;
/*0x800ac250*/ u32 unk144;
};
struct scenariodata_pac {
@ -4787,8 +4760,8 @@ struct scenariodata_pac {
u16 age240;
s32 victimindex;
s16 victims[12]; // shuffled list of player numbers
s16 unk20[12];
s16 wincounts[12]; // indexed by player num
s16 killcounts[12]; // indexed by player num
s16 survivalcounts[12]; // indexed by player num
};
struct scenariodata_koh {