Staredit Network > Forums > Modding Assistance > Topic: StarCraft 64 Co-Op Mod - Enemy AI won't launch scripted attacks
StarCraft 64 Co-Op Mod - Enemy AI won't launch scripted attacks
Today, 2:13 am
By: tokatta007  

Today, 2:13 am tokatta007 Post #1



Hi all,

I've built a 2-player split-screen shared-control co-op hack of StarCraft 64 that runs across all 60 campaign missions (I released it as V1 on romhacking.net + GitHub). It works well, but there's one bug I've spent about two days chasing and can't crack, and I'm hoping someone with deeper SC64 knowledge might be able to help out.

The bug: On script-driven survival missions (clearest example: Terran mission 3, "Desperate Alliance" / 00C.chk), the enemy computer doesn't launch proactive scripted attack waves in co-op like it does in the vanilla game. It builds units, the defense buildings fire, and units occasionally defend when directly attacked, but the zerg ai never sends scripted waves of enemies at the player. In vanilla single-player, the same mission's enemy attacks reliably (~1–3 min in). Missions where the enemy uses autonomous/melee-style AI (T1, T2, T5) attack perfectly fine in co-op. Only the trigger/script-driven survival mission type fails.

What I've verified (live, in the PJ64 debugger, vanilla vs co-op on the same mission):
- Enemy is a valid computer player, correct owner (05) / race, on the same slot (4) in both. The AI did not shift to a different slot in co-op.
- The AI script interpreter (0x800939F0 I think), the command dispatcher (0x800196F8 I think), and the AI-script setup action (0x80073740 I think) all run in co-op, same as vanilla.
- Alliance/hostility is fine. The enemy attacks the human players on the missions that work, so it does consider the human an enemy. And occasionally the enemy will attack the units I send at it on this T3 mission.
- I traced the 2-player flag (0x800AFEFC): 137 read sites, 16 that run during the mission. I force-patched all 16 to take the 1-player path simultaneously, but sadly no change to the enemy. So the bug is NOT a 2p-flag branch.

- The mod's functional changes are: P2 shares P1's slot, a stamp of type=2 into player-3's slot (0x800B0108) for independent P2 control, viewport, and a campaign-load enable at 0x800229B4 that also bumps the player count to 2.
- The clearest data difference is the enemy's per-player AI struct (0x800F0E70 + slot*0x500): in co-op its unit-tracking list has ~10 records vs ~4 in vanilla, but I traced the code that adds them (0x8004AB20 / 0x8004B208) and it registers records keyed by unit type, so I believe that's a symptom of the busier co-op game, not the cause.

My working theory: The no-attack behavior is emergent from the 2-player context. Some timing/ordering difference in the scripted-wave path that doesn't reduce to a single flag or value I can find. But I'd love to be wrong, because that means it's fixable. Currently I'm stumped.

Questions:
1. Does anyone know how SC64's trigger engine handles AI Script/scripted attack activation, and whether the player count or the 2-player launch path changes when or whether that action fires? That's the piece I can't see cleanly.
2. Any docs on the runtime trigger/AI-script data layout in RAM (the trigger data lives around 0x800C0000) would help a lot.

I can share the full list of addresses, my debugger captures, RAM dumps (vanilla vs co-op on Desperate Alliance), and the BPS patch, or whatever's useful. Happy to do any tests someone wants to suggest. Thanks for reading, and thanks for keeping Starcraft alive <3

My mod: https://github.com/Tokatta007/Starcraft-64-Co-Op-Mod

Post has been edited 3 time(s), last time on Today, 2:34 am by tokatta007.



None.

3 hours ago Heinermann Post #2

memes memes memes memes memes memes memes memes memes memes memes memes memes memes memes memes memes memes memes memes memes memes memes memes memes

Starcraft 64 uses almost the same code as the PC ver, it is a true port as far as I could tell. I think maybe the patch turned a UMS (campaign) into a Team game. I think we did this as a hack on PC a long time ago too, but I don't remember what issues it caused if any.

Is the slot that P2 is using not overlapping with other in-game slots? Are they both marked as human-controlled in the same force? If one is marked as something else (i.e. computer/inactive) it might cause a problem. Of course, that's only if SC64 is handling it the same way it would on PC.

Quote
2. Any docs on the runtime trigger/AI-script data layout in RAM (the trigger data lives around 0x800C0000) would help a lot.
It depends on the ROM, I think? The addresses provided don't match the ROM I annotated. I don't know that triggers would impact it, and since Team UMS is not a valid game mode on PC unless hacked in I don't know how the AI interacts with it. I think it's strictly an AIScript issue or slot configuration issue, unless that mission specifically has a trigger that forces an attack wave.

I have only ported some symbols to SC64 to use as a reference for reverse engineering the PC ver. In the reverse engineering project, AI is by far the least understood and least labelled part of the source right now.

I plan to create a thread announcing the project Soon™ with crowdsourcing tasks for non-coders too, but I'd be happy to share stuff early. Let me know if you want source access & I can upload the IDA dbs separately. The IDB I labelled is for `StarCraft 64 (E) [f1] (NTSC).z64`, and the best labelled idb I have is 1.17 followed by MacOS's 1.16.1. If you don't have/use IDA I can dump the symbols into any format you want.

Some structs in SC64 are different i.e. in https://www.decomp.me/scratch/nolS6 (see Context tab) TRIGGERNODE has a pointer to the TRIGGER struct instead of a copy, to reduce memory usage on the N64. You can grab all the enums and related structs from that context tab.

After looking at Terran3 it does run Send All Units on Strategic Suicide Missions after 2 minutes, and runs Terran 3 - Zerg Town at the start.

I've got this for the send suicide opcode lol so not much info
Code
   case AIOPC_SEND_SUICIDE:
     {
       BYTE bSuicideType = aiscript_get_byte(pScp);
       aiscript_attack_clear(pScp->owner, TRUE);
       //sub_4B11B0(pScp->owner, bSuicideType);
       aiscript_quick_attack(pScp->owner, 5);  // TODO def
     }
     break;





59 minutes ago tokatta007 Post #3



Thank you for the quick and detailed reply! This is incredibly helpful.

"Send All Units on Strategic Suicide Missions after 2 minutes" lines up with what I see. In co-op that attack never comes. The enemy runs "Zerg Town" fine (it builds, defends locally), but the suicide wave never fires. Given the opcode you pasted:

aiscript_attack_clear(pScp->owner, TRUE);
aiscript_quick_attack(pScp->owner, 5);

My suspicion is that pScp->owner isn't resolving to the Zerg in the co-op configuration, so quick_attack is pointed at the wrong (or an empty) owner and does nothing. That would explain why every stage I could observe "runs" but no wave appears. The script executes, it's just commanding the wrong player. Does that hold up against how the AI script owner actually gets assigned? And is pScp->owner set once when the script is attached (Run AI Script), or resolved live each time an opcode runs?

So my mod is a shared-control split-screen hack that effectively puts the campaign into Team Melee / Archon mode: both players share one force, one base, one army, and Player 2 is a second cursor, selection, and viewport rather than a separate player with its own units. The core changes are that P2 shares P1's slot for control (patch at 0x8003DF34), P2 gets its own selection context (0x8003DF48), and there's a campaign-load enable at 0x800229B4 that also sets the second_player_active flag (0x800AFEFC) and bumps the active player count to 2. The engine's master player table at 0x800AFF54 (stride 0x24, +0 control where 02 = human occupied, +1 race, +2 local player #) is where the co-op controller config ends up, so if that's what determines the AI script's owner, that's where I'd expect the mismatch to originate.

Your reply is resonating with me since I already hit the same "co-op is classified as multiplayer from launch" behavior in a completely different system. Mid-game Campaign saves and mission progression doesn't save in co-op, and when I traced it, the cause was that second_player_active makes the engine treat the session as multiplayer, so the campaign mission-complete event chain never fires and it ends through a multiplayer results path instead. If that same launch-mode classification also changes how AI script ownership or the force setup resolves, that would explain it.

For reference, Terran 3's OWNR is 07 06 00 00 05 (slot 0 neutral, slot 1 you/human, slots 2 and 3 empty, slot 4 Zerg/computer). Missions where the enemy uses autonomous/melee-style AI attack perfectly fine in co-op. Only the trigger-driven survival type, the ones that rely on that suicide script, fail. That pattern seems consistent with a script-owner or force-resolution problem rather than anything unit or map specific. Or maybe the issue is my mod doesn't like ai script changes?


Two things that would help me a ton:

1. In your annotated source, how is the owner determined for a running AI script? Is there a spot where the Team Melee / multiplayer player config could cause a script to be owned by, or its attack directed at, the wrong player?

2. Yes please to the source, I'd be really grateful <3 I don't actually have IDA, so the reverse-engineered code and the struct and enum definitions are the part I'm missing, more than the IDB itself. A symbol dump or the source in any plain format would be perfect, if it's not too much trouble. Also, I'm on StarCraft 64 (U), so I know your (E)[f1] addresses won't line up directly, but the structs and script logic are exactly what I need.

Really appreciate you taking the time on this. The reverse-engineering project sounds great too, and I'm happy to take a look at it whenever you launch it. Exciting stuff!



None.

Options
  Back to forum
Please log in to reply to this topic or to report it.
Members in this topic: None.
[02:59 am]
lifebot -- scrmaps.com Post Your Map
[02:34 am]
Symmetry -- Power to ya tokatta
[02:34 am]
Symmetry -- Jeez someone's modding SC64? I've never even hear of anyone trying
[02:27 am]
Symmetry -- if you're looking to upload a map put it on scmscx and link it here. the dldb is... inconsistent
[12:51 pm]
Zakerozi -- Lel... This guy is probably a Zoomer :D :D :D
[09:57 am]
NudeRaider -- dydwk474
dydwk474 shouted: HOW DO YOU EVEN UPLOAD FILE HERE THATS BULLCOWAP THE WEBSITE DUMB
mostly magic, but also doing a :wob:-raindance and sacrificing your firstborn. If that sounds like too much effort, just use www.scmscx.com
[09:55 am]
NudeRaider -- Vrael, did you rename your account?
[07:30 am]
dydwk474 -- HOW DO YOU EVEN UPLOAD FILE HERE THATS BULLCOWAP THE WEBSITE DUMB
[07:30 am]
dydwk474 -- WHAT
[2026-8-24. : 1:15 am]
Symmetry -- There are so many people here I'm surprised we're still online :hurr:
Please log in to shout.


Members Online: MobMob, lifebot