For all those looking for a mod to add in more girls... Unfortunately the girls are not added in a static "item" sense... They are referred to as AgentActor [Heroine] in the programming (chara= Agent/Player/Merchant)... I found where they are added... The problem is they are tied to the repair and activation of their capsules [heroine_point]. Therefore, the only way we can add new girls would be:
A: place new capsules via decompressing the current game assets and assemblies, opening the module in Unity, duplicating the animated capsules with attached scripts, placing them in new locations on the map in Unity, then exporting the file package to be applied in the game's mods folder... (I wonder if the room at the back of the lab has the same animated capsules, deleting the box collider and model for that one collapsed capsule shouldn't be too hard to gain access to that back area -- provided it's not just a visual overlay and they are 3d objects in there -- if not we'd need to replace the capsules with the animated one outside, assign a new ID number, and duplicate them throughout that back room... should work in conventional theory)
B: Track down the script that is deleting the functionality of the add girl function in the existing capsules, which would more-or-less be gamebreaking in that you would be able to load infinite girls from the first capsule you find and repair. This would be easier in theory but would be broken in completed games and could possibly cause save corruption, and also would need to be used experimentally and not in excess since I would imagine if you blindly added a dozen girls then went to play there is a possibility the game would freeze completely. Since they are all going to be battling one another for your attention immediately after. We would probably have to add one, run around and test FPS drops, then save, then add another, lather rinse repeat.
C: Lastly, there may be a way to add a module with a UI overlay to simply spawn in an additional girl at your location using a simple location get script and then making it call the spawn of the new girl routine just kind of plopping her on top of you. That would also operate the same as the B: option in general...
I would feel best with A since that would require you to get to the end of the island, but it would also be more work with higher potential of causing deeper issues and breaking more stuff. However, the other two would likely make it easier to break the game in various ways... I dunno, just spitballing...
This is the LoadAgents script that utilizes the capsules:
C:
private IEnumerator LoadAgents(WorldData profile, bool existsBackup)
{
DefinePack define = Singleton<Manager.Resources>.Instance.DefinePack;
AgentProfile agentProfile = Singleton<Manager.Resources>.Instance.AgentProfile;
string bundlePath = define.ABPaths.ActorPrefab;
string manifest = define.ABManifests.Default;
GameObject agentPrefab = CommonLib.LoadAsset<GameObject>(bundlePath, "Agent", clone: false, manifest);
if (!MapScene.AssetBundlePaths.Exists((UnityEx.ValueTuple<string, string> x) => x.Item1 == bundlePath && x.Item2 == manifest))
{
MapScene.AssetBundlePaths.Add(new UnityEx.ValueTuple<string, string>(bundlePath, manifest));
}
int[] chunkKeys = ChunkTable.Keys.ToArray();
int maxCharaNum = Config.GraphicData.MaxCharaNum;
bool[] charasEnter = Config.GraphicData.CharasEntry;
for (int i = 0; i < profile.AgentTable.Count; i++)
{
if (!charasEnter[i] && (!TutorialMode || i != 0))
{
continue;
}
AgentData data = profile.AgentTable[i];
if (!data.OpenState || data.CharaFileName.IsNullOrEmpty())
{
continue;
}
GameObject agentObj = UnityEngine.Object.Instantiate(agentPrefab, ActorRoot);
agentObj.name = string.Format("Heroine_{0}", i.ToString("00"));
AgentActor agent = agentObj.GetComponent<AgentActor>();
agent.ID = i;
agent.AgentData = data;
data.param.Bind(agent);
RegisterActor(i, agent);
RegisterAgent(i, agent);
if (existsBackup)
{
if (!TutorialMode)
{
if (agentProfile.BlackListInSaveAndLoad.Contains(data.ModeType))
{
data.ModeType = Desire.ActionType.Normal;
}
if (data.ModeType == Desire.ActionType.Date || data.ModeType == Desire.ActionType.Onbu)
{
data.ModeType = Desire.ActionType.Normal;
}
}
agent.Mode = data.ModeType;
agent.PrevMode = data.PrevMode;
if (i == 0 && TutorialMode)
{
AgentActor agentActor = agent;
Desire.ActionType actionType2 = data.ModeType = Desire.ActionType.Idle;
actionType2 = actionType2;
agent.PrevActionMode = actionType2;
actionType2 = actionType2;
agent.PrevMode = actionType2;
agentActor.Mode = actionType2;
agent.PrevActionMode = Desire.ActionType.Idle;
agent.TutorialType = data.TutorialModeType;
agent.TutorialMode = true;
TutorialAgent = agent;
agent.CreateTutorialBehaviorResources();
}
Vector3 pos = data.Position;
(from _ in Observable.EveryUpdate()
where agent.NavMeshAgent.enabled
select _).TakeWhile((long _) => !agent.NavMeshAgent.isOnNavMesh).Subscribe(delegate
{
agent.NavMeshAgent.Warp(pos);
});
agent.Rotation = data.Rotation;
ChunkTable.TryGetValue(data.ChunkID, out Chunk value);
MapArea[] mapAreas = value.MapAreas;
foreach (MapArea mapArea in mapAreas)
{
if (mapArea.AreaID == data.AreaID)
{
agent.MapArea = mapArea;
}
}
}
else
{
StoryPoint storyPoint = GetStoryPoint(0);
if (TutorialMode && i == 0 && storyPoint != null)
{
AgentActor agentActor2 = agent;
Desire.ActionType actionType2 = data.ModeType = Desire.ActionType.Idle;
actionType2 = actionType2;
agent.PrevActionMode = actionType2;
actionType2 = actionType2;
agent.PrevMode = actionType2;
agentActor2.Mode = actionType2;
AIProject.Definitions.Tutorial.ActionType actionType6 = agent.TutorialType = (data.TutorialModeType = AIProject.Definitions.Tutorial.ActionType.Idle);
agent.MapArea = storyPoint.OwnerArea;
Transform transform = storyPoint.transform.FindLoop("heroine_point").transform;
AgentActor agentActor3 = agent;
Vector3? vector = transform?.position;
agentActor3.Position = ((!vector.HasValue) ? (storyPoint.Position + Player.Rotation * storyPoint.Forward * 3f) : vector.Value);
AgentActor agentActor4 = agent;
Quaternion? quaternion = transform?.rotation;
agentActor4.Rotation = ((!quaternion.HasValue) ? storyPoint.Rotation : quaternion.Value);
agent.TutorialMode = true;
TutorialAgent = agent;
agent.CreateTutorialBehaviorResources();
}
else
{
int key = 0;
ChunkTable.TryGetValue(key, out Chunk value2);
List<Waypoint> waypoints = value2.MapAreas[0].Waypoints;
List<Waypoint> list = waypoints.FindAll(delegate(Waypoint x)
{
Vector3 position = Player.Position;
float num = Vector3.Distance(x.transform.position, position);
return num > 50f;
});
if (Debug.isDebugBuild)
{
Debug.Log($"近距離で除外されたウェイポイントの数 = {waypoints.Count - list.Count}");
}
Waypoint element = list.GetElement(UnityEngine.Random.Range(0, list.Count));
agent.Position = element.transform.position;
agent.MapArea = value2.MapAreas[0];
}
}
agent.Relocate();
agentObj.SetActiveSafe(isActive: true);
yield return agent.LoadAsync();
if (!existsBackup)
{
agent.SetDefaultImmoral();
foreach (KeyValuePair<int, float> item in agent.ChaControl.fileGameInfo.desireDefVal)
{
agent.AgentData.DesireTable[item.Key] = item.Value;
}
}
yield return null;
}
yield return null;
public void LoadAgentTargetActionPoint()
{
foreach (KeyValuePair<int, AgentActor> agent in _agentTable)
{
ActionPoint actionPoint = PointAgent.ActionPoints.FirstOrDefault((ActionPoint x) => x.RegisterID == agent.Value.AgentData.CurrentActionPointID);
if (actionPoint == null)
{
actionPoint = PointAgent.AppendActionPoints.Find((ActionPoint x) => x.RegisterID == agent.Value.AgentData.CurrentActionPointID);
}
if (actionPoint != null && !actionPoint.AgentEventType.Contains(AIProject.EventType.Move) && !actionPoint.AgentEventType.Contains(AIProject.EventType.DoorOpen))
{
agent.Value.TargetInSightActionPoint = actionPoint;
}
}
}
public void LoadAgentTargetActor()
{
foreach (KeyValuePair<int, AgentActor> item in _agentTable)
{
if (_actorTable.TryGetValue(item.Value.AgentData.ActionTargetID, out Actor value))
{
item.Value.TargetInSightActor = value;
}
}
}
}
This seems to be the script that is activated to actually spawn the girl into the world:
Code:
public AgentActor AddAgent(int id, AgentData agentData)
{
if (_agentPrefab == null)
{
DefinePack definePack = Singleton<Manager.Resources>.Instance.DefinePack;
string bundlePath = definePack.ABPaths.ActorPrefab;
string manifest = definePack.ABManifests.Default;
_agentPrefab = CommonLib.LoadAsset<GameObject>(bundlePath, "Agent", clone: false, manifest);
if (!MapScene.AssetBundlePaths.Exists((UnityEx.ValueTuple<string, string> x) => x.Item1 == bundlePath && x.Item2 == manifest))
{
MapScene.AssetBundlePaths.Add(new UnityEx.ValueTuple<string, string>(bundlePath, manifest));
}
}
int[] array = ChunkTable.Keys.ToArray();
GameObject gameObject = UnityEngine.Object.Instantiate(_agentPrefab, ActorRoot);
gameObject.name = string.Format("Heroine_{0}", id.ToString("00"));
AgentActor component = gameObject.GetComponent<AgentActor>();
component.ID = id;
component.AgentData = agentData;
if (Singleton<Manager.Resources>.Instance.AgentProfile.DefaultAreaIDTable.TryGetValue(id, out int value))
{
int num3 = component.AreaID = (agentData.AreaID = value);
foreach (KeyValuePair<int, Chunk> item in ChunkTable)
{
MapArea[] mapAreas = item.Value.MapAreas;
foreach (MapArea mapArea in mapAreas)
{
if (mapArea.AreaID == value)
{
component.MapArea = mapArea;
}
}
}
}
agentData.param.Bind(component);
RegisterActor(id, component);
RegisterAgent(id, component);
if (Singleton<AnimalManager>.IsInstance())
{
Singleton<AnimalManager>.Instance.AddTargetAnimals(component);
}
component.Relocate();
gameObject.SetActiveSafe(isActive: true);
component.Load();
return component;
}
Then these are used to unload the existing girls from the world:
Code:
public void RemoveAgent(AgentActor agent)
{
agent.DisableBehavior();
agent.BehaviorResources.DisableAllBehaviors();
foreach (KeyValuePair<int, Dictionary<int, UnityEx.ValueTuple<AudioSource, FadePlayer>>> item in agent.Animation.ActionLoopSETable)
{
foreach (KeyValuePair<int, UnityEx.ValueTuple<AudioSource, FadePlayer>> item2 in item.Value)
{
UnityEx.ValueTuple<AudioSource, FadePlayer> value = item2.Value;
if (!(value.Item2 == null))
{
UnityEx.ValueTuple<AudioSource, FadePlayer> value2 = item2.Value;
value2.Item2.Stop(0f);
}
}
}
agent.Animation.ActionLoopSETable.Clear();
Player.PlayerController.CommandArea.RemoveCommandableObject(agent);
UnregisterAgent(agent.ID);
UnregisterActor(agent.ID);
foreach (KeyValuePair<int, AgentActor> item3 in AgentTable)
{
if (!(item3.Value == agent))
{
item3.Value.RemoveActor(agent);
}
}
Singleton<Character>.Instance.DeleteChara(agent.ChaControl);
UnityEngine.Object.Destroy(agent.gameObject);
}
These are found at:
Assembly-CSharp.dll>Manager>Map>Line 2580
Attached a full version of the map.xml file if anyone wants to look at the whole thing and throw about some ideas...