Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

experimental 4player Counter / Co-Operative #389

Closed
wants to merge 75 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
624be55
treat `g_Vars.coop` and `g_Vars.anti` like `g_Vars.currentplayer`
NeonNyan Feb 9, 2024
723326d
patch written by @iamgreaser
iamgreaser Feb 9, 2024
b876dd2
Use vertical-split versions of menus in 3+-player main missions
iamgreaser Feb 8, 2024
ce1ccd5
objective check: check all coop players for required objective item
NeonNyan Feb 11, 2024
7288a55
p1p2_opposite is treated as currentcoopnum
NeonNyan Feb 11, 2024
9e5ab45
4pcoop changes
NeonNyan Feb 11, 2024
370b625
add orgfile tracking 4pcoopanti ailist progress
NeonNyan Feb 11, 2024
116cf5f
if_chr_dead: handle anti/coop
NeonNyan Feb 12, 2024
953c18c
update notes
NeonNyan Feb 12, 2024
1d765ff
`aiChrIfDead` respects `g_Vars.playerorder`
NeonNyan Feb 14, 2024
25f342e
`aiIfChrDeathAnimationFinished` now supports 4pcoop and 4panti
NeonNyan Feb 14, 2024
19c30bf
helper function
NeonNyan Feb 14, 2024
b0ac417
update coopanti notes
NeonNyan Feb 14, 2024
1e4c70f
update notes
NeonNyan Feb 14, 2024
a1151c9
cctvtick will enumerate over all players and break if it finds one bond
NeonNyan Mar 9, 2024
e1c7ad7
setchrflags
NeonNyan Mar 9, 2024
812a120
aiGiveObjectToChr
NeonNyan Mar 9, 2024
6defef9
propobj checks if any coop player is using it
NeonNyan Mar 9, 2024
1d8c359
some helper functions for checking coop / antiness
NeonNyan Mar 9, 2024
eb6baa5
endscreen: setNumPlayers(4)
NeonNyan Mar 9, 2024
327dbb9
update notes
NeonNyan Mar 9, 2024
cae7aef
fixup: 4pcoop: cleanup check
NeonNyan May 27, 2024
76e87ba
4pcoop: spawn radius fix for multiple human players
NeonNyan May 27, 2024
5ff7b2c
4pcoop: remove comment
NeonNyan May 27, 2024
7737d98
4pcoop: fixup solo / coop picking for head / body determination
NeonNyan May 27, 2024
362ff29
4pcoop: shorten the length of time in front of cctv before alarm trips
NeonNyan May 27, 2024
6265827
more reliable isanti check
NeonNyan May 29, 2024
a819fab
increase spawn distance
NeonNyan Jun 12, 2024
3d098ec
fixup: getPlayerPool no longer static
NeonNyan Jun 12, 2024
bdaf629
cycle aiChrUnsetChrflag per-human hench
NeonNyan Jun 12, 2024
5e1281e
cycle aiIfChrActivatedObject between all human henches of that chr type
NeonNyan Jun 13, 2024
cf46f43
refactor helper functions
NeonNyan Jun 13, 2024
a21b482
cycle aiIfChrHasWeaponEquipped
NeonNyan Jun 13, 2024
55d9cdd
fixes aiIfChrActivate
NeonNyan Jun 13, 2024
21cf785
fixup aiIfChrHasWeaponEquipped
NeonNyan Jun 13, 2024
f49f91d
fixup isdead command
NeonNyan Jun 14, 2024
c1e857c
make aiIfChrDistanceToPadGreaterThan support >2 player coop
NeonNyan Jun 14, 2024
89566f1
treat aiIfPlayerLookingAtObject as "any coop"
NeonNyan Jun 16, 2024
377a800
added new helper functions
NeonNyan Jun 16, 2024
54041ef
when coop, make chrGetDistanceToTarget return the min of all coop pla…
NeonNyan Jun 16, 2024
9728a86
treat aiIfCheckFovWithTarget as any
NeonNyan Jun 17, 2024
1206e50
removeme: debug loglines
NeonNyan Jun 17, 2024
51205e4
revert chrGetDistacneToTarget changes
NeonNyan Jun 17, 2024
03ce883
cycle aiIfDistanceToTargetLessThan per coop player
NeonNyan Jun 17, 2024
deb98da
handle aiIfChrHasObject per coop player correctly
NeonNyan Jun 17, 2024
cb51da6
remove debug output
NeonNyan Jun 17, 2024
8ddbaae
Added new mode: Team Missions
NeonNyan Jun 21, 2024
fb48038
Implement player assignment menu
NeonNyan Jul 5, 2024
6c1fcec
supports coop vs anti
NeonNyan Jul 5, 2024
a0adecd
some more fixes to coop / anti scheduling
NeonNyan Jul 5, 2024
300b0db
non-contigious controller assignments work
NeonNyan Jul 5, 2024
bd7d54c
fix windows build issue?
NeonNyan Jul 5, 2024
2dfc783
windows build issue
NeonNyan Jul 5, 2024
c2b7947
windows build issue
NeonNyan Jul 5, 2024
9492e7f
windows bld issue
NeonNyan Jul 6, 2024
065ea92
windows build issue
NeonNyan Jul 6, 2024
bd98988
windows build issue
NeonNyan Jul 6, 2024
b76057a
windows build issue
NeonNyan Jul 6, 2024
263219e
windows build issue
NeonNyan Jul 6, 2024
c4db99e
windows build issues
NeonNyan Jul 6, 2024
7657014
fixup playerroles
NeonNyan Jul 6, 2024
bf00fc1
windows build issue
NeonNyan Jul 6, 2024
0f17391
windows build issue
NeonNyan Jul 6, 2024
8f20166
windows build issue
NeonNyan Jul 6, 2024
7d0d0f4
Renamed "Team Missions" -> Quad-Operative
NeonNyan Jul 6, 2024
c86184a
fix p1p2 scheduling issues
NeonNyan Jul 7, 2024
3202ead
really fix p1p2 scheduling issues
NeonNyan Jul 21, 2024
66101b3
fix player allocation
NeonNyan Aug 18, 2024
97f47bd
use PLAYERCOUNT() instead of MAX_PLAYERS
NeonNyan Aug 18, 2024
cf75ba3
don't set `g_Vars.mplayerisrunning = true` in menus
NeonNyan Aug 18, 2024
044a29d
fixup: aiIfChrDeathAnimationFinished no longer incorrectly marks coop…
NeonNyan Sep 1, 2024
1548ebf
fixup: use seperate continue button handlers for team / coop modes
NeonNyan Sep 1, 2024
dcc6475
coop support for aiRevokeControl
NeonNyan Sep 1, 2024
2fa0b2f
teleportals kind of work
NeonNyan Sep 2, 2024
b030f0c
fixup: this will help us move around the ship quicker
NeonNyan Sep 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 191 additions & 0 deletions docs/4p-coop-anti-notes.org
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
* AI lists using CHR_COOP


These will need to be updated to refer to all valid coop players

** TODO anti compatibility: look at ifChrHasObject to verify that it's only checking coop characters
#+begin_src c
/**
* @cmd 005d
*/
bool aiIfChrHasObject(void)
#+end_src


This was implemented with coop but not anti support

** DONE src/include/commands.h|492 col 1| #define if_chr_dead(chr, label) \

Used on =CHR_COOP= in multiple places.
Also used on =CHR_P1P2=
Not used on =CHR_ANTI=

vanilla: only checks non-player characters, but is called on p1p2 / coop in several places

4player-coopanti: Checks all coop players, anti players, P1P2

coop calls:

#+BEGIN_SRC
src/setups/setuplee.c|2434 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x2c)
src/setups/setuplee.c|2658 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x2c)
src/setups/setuprit.c|1113 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x2d)
src/setups/setuprit.c|1130 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x2d)
src/setups/setupstat.c|1009 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x2d)
src/setups/setupark.c|1404 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x20)
src/setups/setuplip.c|2431 col 3| if_chr_dead(CHR_COOP, /*goto*/ LABEL_2D)
src/setups/setupeld.c|2341 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x2d)
src/setups/setupimp.c|2946 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x2e)
src/setups/setuppam.c|2507 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x61)
src/setups/setuppam.c|2537 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x61)
src/setups/setuppam.c|2551 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x61)
src/setups/setuppam.c|2583 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x61)
src/setups/setuppam.c|2604 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x61)
src/setups/setuppam.c|2618 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x61)
src/setups/setuppam.c|2646 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x61)
src/setups/setuppam.c|2665 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x61)
src/setups/setuppam.c|2694 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x61)
src/setups/setuppam.c|3322 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x2e)
src/setups/setuppam.c|4268 col 3| if_chr_dead(CHR_COOP, /*goto*/ 0x2e)
src/setups/setuplue.c|1325 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x2e)
src/setups/setupame.c|2173 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x2c)
src/setups/setupear.c|2651 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x2f)
src/setups/setuptra.c|2019 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x32)
src/setups/setuptra.c|2270 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x33)
src/setups/setuptra.c|2887 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x06)
src/setups/setupazt.c|1925 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x31)
src/setups/setupazt.c|1943 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x31)
src/setups/setupsev.c|1390 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x2c)
src/setups/setuppete.c|1191 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x03)
src/setups/setupwax.c|1903 col 3| if_chr_dead(CHR_COOP, /*goto*/ 0x2c)
src/setups/setupcave.c|2308 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x31)
src/setups/setupcave.c|2333 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x31)
src/setups/setupdepo.c|1466 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x2c)
src/setups/setupdam.c|1222 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x07)
src/setups/setupdam.c|1239 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x07)
src/setups/setupsho.c|2526 col 2| if_chr_dead(CHR_COOP, /*goto*/ 0x2d)
#+end_src

however, there is only one instance of a p1p2 call:

#+begin_src log
src/setups/setupdepo.c|1429 col 3| if_chr_dead(CHR_P1P2, /*goto*/ 0x2c)
#+end_src
New behavior:

- if non-player: default behavior
- if p1p2: check all players.
- if coop: check all coop (not bond, not anti) players
- if anti: check all anti (not bond, not coop) players

** DONE src/include/commands.h|500 col 1| #define if_chr_death_animation_finished(chr, label) \


Used on =CHR_ANTI=, =CHR_COOP=, =CHR_P1P2=

#+begin_src c
/**
* @cmd 0034
*/
bool aiIfChrDeathAnimationFinished(void)
#+end_src

vanilla: checks single player if prop of chr is =PROPTYPE_PLAYER=

4playercoop: if bond, check bond. if anti, check anti playerpool. if coop/p1p2, check coopplayer pool. otherwise check generic playerpool,

** TODO =void cctvTick(struct prop *camprop)=

vanilla: This cylces between coop and bond alternating frames.

** TODO src/include/commands.h|688 col 1| #define if_chr_in_onscreen_room(chr, label) \
** TODO src/include/commands.h|830 col 1| #define if_chr_distance_to_pad_lt(chr, distance, pad, label) \
** TODO src/include/commands.h|841 col 1| #define if_chr_distance_to_pad_gt(chr, distance, pad, label) \
** TODO src/include/commands.h|902 col 1| #define if_chr_in_room(chr, type, room_or_pad, label) \
** COOP src/include/commands.h|921 col 1| #define if_chr_has_object(chr, object, label) \
* TODO src/include/commands.h|948 col 1| #define if_chr_weapon_equipped(chr, weapon, label) \
#+begin_src
if_chr_weapon_equipped(CHR_BOND, WEAPON_DATAUPLINK, /*goto*/ 0x2f)
if_chr_weapon_equipped(CHR_BOND, WEAPON_DOORDECODER, /*goto*/ 0x06)
if_chr_weapon_equipped(CHR_BOND, WEAPON_DOORDECODER, /*goto*/ 0x2f)
if_chr_weapon_equipped(CHR_BOND, WEAPON_ECMMINE, /*goto*/ 0x2f)
if_chr_weapon_equipped(CHR_BOND, WEAPON_EYESPY, /*goto*/ 0x2f)
if_chr_weapon_equipped(CHR_BOND, WEAPON_FARSIGHT, /*goto*/ 0x2e)
if_chr_weapon_equipped(CHR_BOND, WEAPON_LAPTOPGUN, /*goto*/ 0x0b)
if_chr_weapon_equipped(CHR_BOND, WEAPON_LASER, /*goto*/ 0x0f)
if_chr_weapon_equipped(CHR_BOND, WEAPON_NIGHTVISION, /*goto*/ 0x2f)
if_chr_weapon_equipped(CHR_BOND, WEAPON_XRAYSCANNER, /*goto*/ 0x2f)
if_chr_weapon_equipped(CHR_COOP, WEAPON_FARSIGHT, /*goto*/ 0x2f)
if_chr_weapon_equipped(CHR_COOP, WEAPON_LASER, /*goto*/ 0x0f)
if_chr_weapon_equipped(CHR_P1P2, WEAPON_AUTOSURGEON, /*goto*/ 0x32)
if_chr_weapon_equipped(CHR_P1P2, WEAPON_BACKUPDISK, /*goto*/ 0x2e)
if_chr_weapon_equipped(CHR_P1P2, WEAPON_CALLISTO, /*goto*/ 0x93)
if_chr_weapon_equipped(CHR_P1P2, WEAPON_DATAUPLINK, /*goto*/ 0x03)
if_chr_weapon_equipped(CHR_P1P2, WEAPON_DATAUPLINK, /*goto*/ LABEL_2D)
if_chr_weapon_equipped(CHR_P1P2, WEAPON_DEVASTATOR, /*goto*/ 0x92)
if_chr_weapon_equipped(CHR_P1P2, WEAPON_DOORDECODER, /*goto*/ 0x2c)
if_chr_weapon_equipped(CHR_P1P2, WEAPON_EXPLOSIVES, /*goto*/ 0x2e)
if_chr_weapon_equipped(CHR_P1P2, WEAPON_FALCON2_SCOPE, /*goto*/ 0x94)
if_chr_weapon_equipped(CHR_P1P2, WEAPON_MAULER, /*goto*/ 0x96)
if_chr_weapon_equipped(CHR_P1P2, WEAPON_MAULER, /*goto*/ LABEL_65)
if_chr_weapon_equipped(CHR_P1P2, WEAPON_NONE, /*goto*/ 0x03)
if_chr_weapon_equipped(CHR_P1P2, WEAPON_SKEDARBOMB, /*goto*/ 0x2c)
if_chr_weapon_equipped(CHR_P1P2, WEAPON_SLAYER, /*goto*/ 0x95)
if_chr_weapon_equipped(CHR_P1P2, WEAPON_SUITCASE, /*goto*/ 0x02)
if_chr_weapon_equipped(CHR_P1P2, WEAPON_UNARMED, /*goto*/ 0x03)
#+end_src
** TODO src/include/commands.h|980 col 1| #define if_chr_activated_object(chr, object, label) \
** TODO src/include/commands.h|1249 col 1| #define if_chr_health_gt(chr, health, label) \
** TODO src/include/commands.h|1258 col 1| #define if_chr_health_lt(chr, health, label) \
** TODO src/include/commands.h|1375 col 1| #define if_chr_alertness_lt(value, chr, label) \
** TODO src/include/commands.h|1538 col 1| #define if_chr_has_flag_bankx(chr, flag, bank, label) \
** TODO src/include/commands.h|1631 col 1| #define if_chr_has_chrflag(chr, chrflag3, label) \
** TODO src/include/commands.h|2459 col 1| #define if_chr_target_eq(chr1, chr2, anytarget, label) \
** TODO src/include/commands.h|2530 col 1| #define if_chr_shield_lt(chr, value, label) \
** TODO src/include/commands.h|2539 col 1| #define if_chr_shield_gt(chr, u1, label) \
** TODO src/include/commands.h|2666 col 1| #define if_chr_has_hiddenflag(chr, chrflag2, label) \
** TODO src/include/commands.h|2677 col 1| #define if_chr_is_human(chr, label) \
** TODO src/include/commands.h|2685 col 1| #define if_chr_is_skedar(chr, label) \
** TODO src/include/commands.h|2989 col 1| #define if_chr_in_squadron_doing_action(action, label) \
** TODO src/include/commands.h|3180 col 1| #define if_chr_listening(chr, listenvalue, checktype, label) \
** TODO src/include/commands.h|3248 col 1| #define if_chr_injured_target(chr, label) \
** TODO src/include/commands.h|3273 col 1| #define if_chr_shield_damaged(chr, label) \
** TODO src/include/commands.h|3278 col 1| #define if_chr_idle_action_eq(action, label) \
** TODO src/include/commands.h|3289 col 1| #define if_chr_y(chr, value, operator, label) \
** TODO src/include/commands.h|3462 col 1| #define if_chr_knockedout(chr, label) \
#+begin_src
if_chr_knockedout(CHR_BOND, /*goto*/ 0x03)
if_chr_knockedout(CHR_BOND, /*goto*/ 0x07)
if_chr_knockedout(CHR_BOND, /*goto*/ 0x08)
if_chr_knockedout(CHR_BOND, /*goto*/ 0x20)
if_chr_knockedout(CHR_BOND, /*goto*/ 0x26)
if_chr_knockedout(CHR_BOND, /*goto*/ 0x27)
if_chr_knockedout(CHR_BOND, /*goto*/ 0x2c)
if_chr_knockedout(CHR_BOND, /*goto*/ 0x2d)
if_chr_knockedout(CHR_BOND, /*goto*/ 0x2e)
if_chr_knockedout(CHR_BOND, /*goto*/ 0x2f)
if_chr_knockedout(CHR_BOND, /*goto*/ 0x31)
if_chr_knockedout(CHR_BOND, /*goto*/ 0x32)
if_chr_knockedout(CHR_BOND, /*goto*/ 0x33)
if_chr_knockedout(CHR_BOND, /*goto*/ 0x61)
if_chr_knockedout(CHR_BOND, /*goto*/ LABEL_2D)
if_chr_knockedout(CHR_COOP, /*goto*/ 0x03)
if_chr_knockedout(CHR_COOP, /*goto*/ 0x06)
if_chr_knockedout(CHR_COOP, /*goto*/ 0x07)
if_chr_knockedout(CHR_COOP, /*goto*/ 0x20)
if_chr_knockedout(CHR_COOP, /*goto*/ 0x2c)
if_chr_knockedout(CHR_COOP, /*goto*/ 0x2d)
if_chr_knockedout(CHR_COOP, /*goto*/ 0x2e)
if_chr_knockedout(CHR_COOP, /*goto*/ 0x2f)
if_chr_knockedout(CHR_COOP, /*goto*/ 0x31)
if_chr_knockedout(CHR_COOP, /*goto*/ 0x32)
if_chr_knockedout(CHR_COOP, /*goto*/ 0x33)
if_chr_knockedout(CHR_COOP, /*goto*/ 0x61)
if_chr_knockedout(CHR_COOP, /*goto*/ LABEL_2D)
if_chr_knockedout(CHR_P1P2, /*goto*/ 0x2c)
#+end_src
** TODO src/include/commands.h|3514 col 1| #define if_chr_looking_at_object(chr, object, label) \
** TODO src/include/commands.h|3565 col 1| #define if_chr_soundtimer(value, operator, label) \
** TODO src/include/commands.h|3795 col 1| #define if_chr_not_talking(chr, label) \
** TODO src/include/commands.h|4337 col 1| #define if_chr_same_floor_distance_to_pad_lt(chr, distance, pad, label) \
* AIlist
18 changes: 13 additions & 5 deletions port/src/pdmain.c
Original file line number Diff line number Diff line change
Expand Up @@ -440,26 +440,34 @@ void mainLoop(void)
}

if (numplayers < 2) {
g_Vars.bondplayernum = 0;
g_Vars.coopplayernum = -1;
g_Vars.antiplayernum = -1;
playermgrDisableTeamPlayers();
} else if (argFindByPrefix(1, "-coop")) {
g_Vars.bondplayernum = 0;
g_Vars.coopplayernum = 1;
g_Vars.antiplayernum = -1;
} else if (argFindByPrefix(1, "-anti")) {
g_Vars.bondplayernum = 0;
g_Vars.playerroles[g_Vars.bondplayernum] = PLAYERROLE_BOND;
g_Vars.coopplayernum = -1;
g_Vars.antiplayernum = 1;
}

playermgrAllocatePlayers(numplayers);
if (g_MissionConfig.isteam) {
playermgrResetTeamPlayers();
}


playermgrAllocatePlayersFromRoles();

if (argFindByPrefix(1, "-mpbots")) {
g_Vars.lvmpbotlevel = 1;
}

if (g_Vars.coopplayernum >= 0 || g_Vars.antiplayernum >= 0) {
if (g_MissionConfig.isteam) {
g_MpSetup.chrslots = 0x0f;
mpReset();
}
else if (g_Vars.coopplayernum >= 0 || g_Vars.antiplayernum >= 0) {
g_MpSetup.chrslots = 0x03;
mpReset();
} else if (g_Vars.perfectbuddynum) {
Expand Down
115 changes: 115 additions & 0 deletions src/game/chr.c
Original file line number Diff line number Diff line change
Expand Up @@ -6670,3 +6670,118 @@ void chrSetDrCarollImages(struct chrdata *drcaroll, s32 imageleft, s32 imagerigh
}
}
}

bool isChrNumCoop(u32 chrnum) {
if (g_Vars.coopplayernum < 0) {
return false;
}

for (s32 i = 0; i < PLAYERCOUNT(); i++) {
if (g_Vars.coopplayers[i] && g_Vars.coopplayers[i]->prop && g_Vars.coopplayers[i]->prop->chr->chrnum == chrnum) {
return true;
}
}

return false;
}


bool isChrTargetCoop(struct chrdata *chr) {
if (g_Vars.coopplayernum < 0) {
return false;
}

struct prop *prop = chrGetTargetProp(chr);

for (s32 i = 0; i < PLAYERCOUNT(); i++) {
if (g_Vars.coopplayers[i] && g_Vars.coopplayers[i]->prop == prop) {
return true;
}
}

return false;
}

bool isChrHumanCoop(struct chrdata *chrdata, u32 chrid) {
// resolve it agaisnt the chrdata table
u32 chrnum = chrResolveId(chrdata, chrid);
// then check if the prop is a known coop player
return isChrNumCoop(chrnum);
}

// BUG: this should also attempt to figure out from chrnum
bool isChrIdMpHumanHench(u32 chrId) {
if (PLAYERCOUNT() < 2) {
return false;
}
switch (chrId) {
case CHR_COOP:
case CHR_ANTI:
case CHR_P1P2:
case CHR_P1P2_OPPOSITE:
// TODO: isChrIdTargetCoop
// case CHR_TARGET:
return true;
}
return false;
}

// BUG: this should also attempt to figure out from chrnum
bool isChrIdMpHumanCoop(u32 chrId) {
if (PLAYERCOUNT() < 2) {
return false;
}
switch (chrId) {
case CHR_COOP:
case CHR_P1P2:
case CHR_P1P2_OPPOSITE:
// case CHR_TARGET:
return true;
}
return false;
}

// BUG: this should also attempt to figure out from chrnum
bool isChrIdMpHumanAnti(u32 chrId) {
if (PLAYERCOUNT() < 2) {
return false;
}
return chrId == CHR_ANTI;
}

bool isChrPropCoop(struct prop *prop) {
if (g_Vars.coopplayernum < 0) {
return false;
}
for (s32 i = 0; i < PLAYERCOUNT(); i++) {
if (g_Vars.coopplayers[i] && g_Vars.coopplayers[i]->prop == prop) {
return true;
}
}
return false;
}

void chrSetTarget(struct chrdata *chr, u16 newtarget, bool isplayer) {
if (newtarget != chr->target) {
chr->lastvisibletarget60 = 0;
chr->lastseetarget60 = 0;
chr->lastheartarget60 = 0;
if (!isplayer) {
chr->hidden &= ~CHRHFLAG_IS_HEARING_TARGET;
chr->chrflags &= ~CHRCFLAG_NEAR_MISS;
}
chr->target = newtarget;
}
}

void chrSetTargetProp(struct chrdata *chr, struct prop *target) {
s16 newtarget;
newtarget = propGetIndexByChrId(chr, target->chr->chrnum);

// @hack: Unsetting these flags here causes guards to become deaf in
// co-op mode. This is because their AI scripting toggles their
// target between the two players on each frame, so this flag is
// cleared before it is read. A suitable fix would be to only unset
// these flags if either the old or new target is not a player.
chrSetTarget(chr, newtarget, chr->prop->type == PROPTYPE_PLAYER || target->type == PROPTYPE_PLAYER);
}
12 changes: 7 additions & 5 deletions src/game/chraction.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "game/sparks.h"
#include "game/stagetable.h"
#include "game/tex.h"
#include "game/title.h"
#include "game/wallhit.h"
#include "bss.h"
#include "lib/joy.h"
Expand Down Expand Up @@ -14161,7 +14162,7 @@ void chrsClearRefsToPlayer(s32 playernum)

if (g_Vars.coopplayernum >= 0) {
if (playernum == g_Vars.bondplayernum) {
otherplayernum = g_Vars.coopplayernum;
otherplayernum = g_Vars.currentallyplayernum;
playerpropnum = g_Vars.bond->prop - g_Vars.props;
} else {
otherplayernum = g_Vars.bondplayernum;
Expand Down Expand Up @@ -14228,15 +14229,16 @@ s32 chrResolveId(struct chrdata *ref, s32 id)
{
u32 index = g_Vars.coopplayernum >= 0 ? ref->p1p2 : g_Vars.bondplayernum;
struct player *player = g_Vars.players[index];
if (player && player->prop && player->prop->chr) {
if (player && player->prop && player->prop->chr && !g_Vars.antiplayers[index]) {
id = player->prop->chr->chrnum;
}
}
break;
case CHR_P1P2_OPPOSITE:
if (g_Vars.coopplayernum >= 0) {
struct player *player = g_Vars.players[1 - ref->p1p2];
if (player && player->prop && player->prop->chr) {
s32 index = (MAX_PLAYERS-1)-ref->p1p2;;
struct player *player = g_Vars.players[index];
if (player && player->prop && player->prop->chr && !g_Vars.antiplayers[index]) {
id = player->prop->chr->chrnum;
}
}
Expand Down Expand Up @@ -15036,7 +15038,7 @@ bool chrAdjustPosForSpawn(f32 chrradius, struct coord *pos, RoomNum *rooms, f32
#else
// On Defection some floating point precision issues result in P2 being placed in the way of P1's cutscene animation,
// which makes P1 start stuck in P2 in coop, so the distance is increased to 80 to avoid that
const f32 distance = (g_Vars.stagenum == STAGE_DEFECTION) ? 80.f : 60.f;
const f32 distance = 80.0f + (COOPPLAYERCOUNT() * 10.f);
for (i = 0; i < 8; i++) {
testpos.x = pos->x + sinf(curangle) * distance;
testpos.y = pos->y;
Expand Down
Loading
Loading