swars
swars copied to clipboard
Enhancement: Customize the looks of your agents
Wouldn't it be nice if you could customize the looks of your agents, to make them look less generic? The game already uses some alternative skins for NPCs you encounter during missions.
For agents we have:
- Standard look
- Blone hair (seen in Church mission 9)
- Red/brown hair (also Church mission 9)
- Red/brown with ponytail (Church mission 12)
For the acolytes, there's the purple robes you see in the later missions.
For the unguided, males seem to have only one skin, but females have a blue hair and blonde hair variant in addition to the default one, seen in EuroCorp mission 14 (Tokyo).
Yeah, this could be nice and give them a bit more personality (although arguably the point of the game is they don't have any!). This is already being done randomly for female unguided in the early level file formats. I guess one way it could be done for player agents is something like given them certain colours based on the first letter of their name or something. That way it would be persistent between levels without having to save the choice in the save game file.
I'm not so sure it's a good idea to make your agents unique this way.. the whole idea is treating them as tools and not humans.
But I would suggest more variation within missions - instead of recognizing your agents, you'd be able to recognize the enemies when repeating hard missions. That is something which would enrich the game more, IMO.
And for Unguided campaign, your group should definitely be as diverse as possible - individualism is part of their ideology.
Currently, unguided are randomized only when converting from old format (as within new format, the diverse look should be a part of level file). Related code: https://github.com/mefistotelis/swars/blob/c2c23715775a111cd2a803b43f5e19268dd912fe/src/thing.c#L247
I haven't really done anything yet with the unguided missions that you two worked on, though I had a feeling they could/should be randomized, makes sense as you just have random missions with control over random units instead of your dedicated team.
For agents and acolytes, I thought having the looks of your 4 active agents (depending on agent number, not on who it actually is) in an ini file, and set a value depending on available looks. Seeing enemy agents with that unique hair has always made me jealous that I couldn't have the same for my generic looking guys.
I've looked around a bit in the code and it looks like the part that draws the sprites of player controlled units isn't remade yet, only the NPC stuff, at least I didn't find anything.
But I would suggest more variation within missions - instead of recognizing your agents, you'd be able to recognize the enemies when repeating hard missions. That is something which would enrich the game more, IMO.
You mean giving special looks to agents depending how upgraded they are? The game does this in a few missions already (EuroCorp mission 8 and two parts of mission 7, the unique agents you need to persuade have different hair), but not in others.
Personally I never really found much difference in practice between enemies and how tough they are, when I get overwhelmed it's almost always from getting in contact with multiple groups of enemies at once. The noteable exception being the zealots with the purple robes which are tough as hell, but they're already marked as such. Oh, and that one scientist guy on the moon with the Graviton Gun, who single-handedly ended my run as the last enemy alive when I thought I had it in the bag for sure during my first playthrough.
Personally I never really found much difference in practice between enemies and how tough they are, when I get overwhelmed it's almost always from getting in contact with multiple groups of enemies at once.
Good point. Yeah, taking that into account, it would make more sense that only your team and VIP enemies are made unique.
I do find the idea of adding more enemy variation intriguing, like generic look for unupgraded agents, red/brown hair for for those with level 1 mods, yellow hair for level 2, etc., like many games have later enemies just being palette swaps of early enemies. But at the same time, being able to tell such a thing by looks can give you an unfair advantage, like who to persuade instead of kill. But a mod to at least make unique enemies stand out more could be nice - take for example EuroCorp mission 7: in Beijing and Phoenix, the target agents have unique hair while the lower ranking ones look generic, but in Hong Kong the target agents looks generic like all the others.
Though the point of this topic was more about your own units, to give options to make them less boring. If you look at the first Syndicate game, your agents' hats (?) had your company color, while enemy agents of different syndicates had differently colored hats.
After fighting my way through 20 missions, I no longer feel that my agents and zealots are generic mooks like all the others whose bodies I walked over - they are elite.
I've tried to look at this. but it looks difficult.
The sprites are in the MSPR-1 to MSPR-5 files. The 5 files look like they're copies with mostly the same content except for different colored agent uniforms. Agents' sprites are separated into body (without head) and head.
I've identified a few sprites of interest: Agent: 0-166 with heads at the start. It's hard to see which heads belong to what character with the images being so tiny. Other non-agent characters sometimes use separate heads too. Long hair: 302-307 seems to be from the female Unguided, but I don't see any other hair of that style, so the agents use the same one? Zealot (regular): 735-770, 901-954 Zealot (elite): 2297-2387
You're pretty close, how it works is that the agents and female unguided do indeed share the same heads. If you see a female unguided with blonde hair it's literally an agent head (hence no ponytail). I'm pretty sure there is at least one level with female unguided hair on a Syndicate Agent. Each character has a predtermined default head graphic, but there is the FrameID value that can be set in level files that overrides and sets a new hair type, any code that would change it would modify this. This already happens with the pre-alpha levels for female unguided randomly as a nice enhancement in the port.
I will hopefully release my level editor thingy soon now it can do most things, at the worst you could manually do it like that, but it would just hardcode each agent to whatever you set it to, and you would have to do it on every level to make them customised.
So they do share heads, even the blondes...
I'm pretty sure there is at least one level with female unguided hair on a Syndicate Agent
In Church mission 12, next to Drennan:
FrameID
So, rather than changing looks directly you could globally set this FrameID for your agents in the code on a campaign basis, excluding missions with Agent Wu and De Saxo?
So, rather than changing looks directly you could globally set this FrameID for your agents in the code on a campaign basis, excluding missions with Agent Wu and De Saxo?
Yes, that's exactly it. You would need to check a few things:
- The character is in group 0 (player group)
- The character is of Type SubTT_PERS_AGENT (this would stop e.g. Agent Wu from being altered as well as not taking effect in the zealot campaign)
Then you would set the first FrameID value to be the desired numbers (FrameID is actually 5 individual bytes, I think the other ones set other body parts, but I've never seen them use, you only want the first byte FrameId.Version[0]). I don't actually know what values are possible for agents, 0 is always default, 1 was blonde hair for unguided, and 2 was blue.
So I guess you would need some place to set them, I guess in the rules.ini or whatever, I imagine as something like myvariable = 1,2,3,4 in there and then force those values on the FrameIDs of the characters fitting the criteria above. The code for pre-alpha levels is very close to what you want, but that is setting based on a random number:
https://github.com/swfans/swars/blob/bc4bfe26025bb0b1c8798be0ae5461954ed78283/src/thing.c#L1001-L1010
EDIT: I tried out different numbers, in fact you can set these:
0 = Default 1 = Blond 2 = Red with ponytail 3 = Red no ponytail
Anything past that you get an agent with no head.
One big problem I discovered though, is that it seems FrameID in the level file is overridden by something for agents, probably because of the customisation options in the game. It works for non-player agents, but is not upheld by player characters when set in the level. Possibly setting it in the code as above might work, I have no idea where it gets forced to zero elsewhere. This doesn't happen for Unguided as players, for sure.
I have no idea where it gets forced to zero elsewhere.
Within make_group_into_players()
- you can comment it out.
So this is where it's at!
I originally planned to add a new file, something like:
agent_cosmetics.ini
; Customizes the looks of your agents
[EuroCorp]
; 0 = default, 1 = yellow hair, 2 = ponytail, 3 = red hair
Agent1=0
Agent2=0
Agent3=0
Agent4=0
[Church]
; 0 = default, 1 = high priest
Agent1=0
Agent2=0
Agent3=0
Agent4=0
and read the values into variables which then will be used there to set the FrameID. Though I'm not much of a programmer so I'm failing spectacularly and for now just settled to set the values directly instead, using some horrible spaghetti code
// Set FrameId for Agents' heads
if (p_person->SubType == SubTT_PERS_AGENT) {
if (plagent == 0)
p_person->U.UPerson.FrameId.Version[0] = 0;
else if (plagent == 1)
p_person->U.UPerson.FrameId.Version[0] = 1;
else if (plagent == 2)
p_person->U.UPerson.FrameId.Version[0] = 3;
else
p_person->U.UPerson.FrameId.Version[0] = 2;
}
...instead of a for loop which would probably be used here by someone competent.
It works with agents so I can at least customize my own game with that. I've also tried to find the high priest skin for the zealots, but nothing I've tried so far has worked. Do characters without separate heads not use FrameID at all?
It works with agents so I can at least customize my own game with that. I've also tried to find the high priest skin for the zealots, but nothing I've tried so far has worked. Do characters without separate heads not use FrameID at all?
Good work!
Now the elite zealots are literally a different character entirely, changing FrameIDs is not going to work. My understanding how the graphics used to define a character is done through two variables, StartFrame and Frame. Startframe seems to be to define the start of a "set" of animation frames for a character, these are uniform for a character type throughout a level file (for example, Zealots use a value of 112). Then there is Frame, which I believe is more dynamic and just shows the specific frame to start on (so for example characters facing different ways will use different Frames even though they are the same character type).
The problem is I can't prove this as setting them differently in a level file doesn't work (that includes random NPCs and not just player characters). I think they are sanitised to keep things uniform based on Thing value (from e.g. ushort people_frames[SubTT_PERS_COUNT]?), but I will defer to superior knowledge on this.
But anyway, cutting to the chase I believe you would need to replace at the very least the StartFrame of your zealots (112) to be that of the Elite Zealots (800).
but I will defer to superior knowledge on this.
How frames are computed differs between thing types. For people, see reset_person_frame()
.
It clearly shows that StartFrame
comes from AnimMode
and people_frames[][] 2D array.
Then, Frame
comes from StartFrame
and Angle
, which make up and an index of the frame value in data/nsta-0.ani
.
Improved code, does this look useable?
Now we would need a way to read the values of PlayerAgentHeads[]
from an .ini file instead of setting it in the code. I've tried using existing code that reads from files like rules.c/rules.h as a base while renaming functions and removing unnecessary code, but so far all my attempts have failed completely.
As for the Zealots, it looks difficult. Something like
if (p_person->SubType == SubTT_PERS_ZEALOT) {
person_anim = people_frames[SubTT_PERS_HIGH_PRIEST][p_person->U.UPerson.AnimMode];
}
can turn regular Zealots temporarily into High Priests, but resets back to white robes as soon as they start an animation like running or shooting, also it only works for some but not others, and not at all for the player.
I've been running in circles for days now, @mefistotelis would you be able to take a look at https://github.com/geist22/swars/tree/Agent-Cosmetics?
I'm trying to get an array PlayerAgentHeads[4]
filled with numbers read from agent_cosmetics.ini
, one for each agent.
Important parts are:
-
/conf/agent_cosmetics.ini
-
agent_cosmetics.c
andagent_cosmetics.h
. Most of the code is recycled copypaste from yourrules.c
doing the reading through the .ini file, changing the names and filling in the blanks. But there's several things wrong. It doesn't compile unlesscase 0
at the end is removed. With a compiled version, the log file prints anUnrecognized command
entry for everyAgentX=X
line in the .ini file. And the comments in the .ini file starting with;
seem to interfere with the reading too, even though they work for me in other .ini files. -
game.c
line 4445 should call the function -
game.c
lines 4084-4090 should setFrameId
for agents. I figured that the function this code is inside is already looping through agent numbers so I've removed the loop and simplified it down to a single line, it seems to work.
There should also be a way to set entries in PlayerAgentHeads[]
to 0 if the .ini file contains invalid entries (anything outside 0-3) or doesn't exist, but I'm not sure where to best do that.
With things looking this messy it might be better to create a clean agent_cosmetics.c
and agent_cosmetics.h
from scratch. Obviously I still have no idea what I'm doing.
@geist22 this should be enough to fix your branch:
diff --git a/src/agent_cosmetics.c b/src/agent_cosmetics.c
index 0a612d7..131dafe 100644
--- a/src/agent_cosmetics.c
+++ b/src/agent_cosmetics.c
@@ -25,7 +25,7 @@
/******************************************************************************/
enum AgentCosmeticsAgentConfigCmd {
- ACAgentCmd_Agent1,
+ ACAgentCmd_Agent1 = 1,
ACAgentCmd_Agent2,
ACAgentCmd_Agent3,
ACAgentCmd_Agent4,
@@ -143,10 +143,8 @@ TbBool read_agent_cosmetics_file(void)
PlayerAgentHeads[3] = k;
CONFDBGLOG("%s %d", COMMAND_TEXT(cmd_num), (int)PlayerAgentHeads[3]);
break;
- /* TODO getting compile errors about duplicates while this is enabled - why?
case 0: // comment
break;
- */
case -1: // end of buffer
case -3: // end of section
done = true;
The C standard does not say which value is used as first for enums. Some compilers use 1, other 0. If you want to be sure, you have to set it directly.
Great, thanks!
With this, changing hairstyle for agents from ini file actually works now! I've also added a condition to leave it at default and log a warning if the entries are invalid.
Would this be alright for a PR?
Would this be alright for a PR?
While I'm not sure how the look customization should be solved, reading these from INI file doesn't seem a best solution to me.
- I think the look should be assigned per-agent, as in cryo content, rather than to agent slots 1,2,3,4 - the ones you take to a mission.
- I'm not sure about how this should be customized, but INI file doesn't sound right. Maybe the option should be in the cryo screen? And maybe a separate screen should be made? Besides hair color, we could also make trenchcoat color to be customizable per-agent.
I do think having a simple and straightforward implementation to achieve this in an easy way would be best - at least that's what I've always had in mind for this. What you suggest sounds like a much more involved process and on a different scope.
I don't know about agent uniform colors. This wasn't originally part of my intention with this, though I've been thinking about it as well. My idea was that different "teams" could have different colored uniforms, like in the previous game where agents had their company color on their hats (or hair?), so you could tell agents belonging to different syndicates apart. But SWARS doesn't really have those missions with multiple syndicates all sending their agents into a free for all battle...
Your agents having a different color than other groups rather than you changing colors for ALL agents could be a welcome addition. Though I think all your agents should have the same color, as they belong to the same team.