Breathing Life Into The Merchant Class
- Right now, merchants are instantiated from prefabs in a sector where the player is. That’ll be altered according to the following plans.
- I need a new data object which represents everything about a merchant. This data object will be used to record an NPC “personality” in the Master Data Store so I can create “named NPCs” that the player will (hopefully) run into here and there to provide some kind of familiarity over the course of play. Yes, I will name them after people I know, with their permission.
- Some of the more important properties of this data object that will help in the simulation would be the current route, the current sector, the origin and destination stations, a simulation timer, wallet, and current cargo inventory.
- The NPCs would be loaded from the MDS (new game) or from the state file (save game) and put into the merchant pool. This will be what we’ll reference when we need to simulate NPC activity.
- Every simulation tick, we’ll check on NPCs to see what they’re doing right now, and what they need to do next:
- If they’re docked at a station, they need to calculate a destination sector and station based on the goods they have purchased (probably the lowest cost SELL that they can afford and/or fit in their holds). Then they’ll undock and move to the next sector and wait for the next tick.
- If they are “in space”, they’ll move to the next sector in their route.
- If they are “in space” and their next sector is their destination sector, they’ll dock at the destination station, sell their goods, buy new goods, and wait for the next tick in order to undock.
- If it’s determined during the sim update that their current sector is the same sector that holds the player (via global CurrentSector property used to track the player), then we need to slow things down and instantiate a merchant for visibility
- The NPC data object will have a reference to a model which will be stored in state so we have uniformity throughout the rest of the game.
- The model will be instantiated and the relevant data copied from the data object to the appropriate component properties (mostly ship info, but also data object ID for refer-back to the global data store)
- Where the model is instantiated will depend on what the NPC is planning to do next:
- If they need to leave a station, they’ll appear outside their current station. They’ll then move to the jumpgate which leads to the next sector in their route. Jumpgate mechanics will handle the Destroy() and will put the NPC back into “sim mode”.
- If they are passing through a sector to the next sector, they will appear at whatever jumpgate leads to their previous sector. They’ll then move to the jumpgate that leads to their next sector. Again, gate mechanics will handle putting them back into background sim mode.
- If they need to dock at a station in that sector, they will appear at a gate leading to their previous sector, and will move to the station. Once inside the station, they’ll sell and buy as normal via the sim, and will wait for the next tick. If the player is still there, they’ll appear and move. If the player has left, they’ll undock in background sim mode and restart their rounds.
- In the cases where the NPC is buying and selling, none of the activities happen on the prefab; they’ll still happen in the simulation layer (wallet amount, cargo inventory, etc). The prefab instance will have no info on aside from a pointer back to the global data object, and any info we need to use to present a visual to the player (model ID, name, portrait, or whatever).
So I guess I need to answer the question “why bother”? This seems like a lot of work for something that the player won’t see, and which could probably be modeled easier by randomly instantiating NPCs here and there, and just redistributing commodities via a background process.
The main goal is to allow players to ID NPCs by name. I want there to be some kind of investment in the universe, and when things become familiar, we tend to feel some kind of kinship or ownership of those familiar elements. Even if there’s no direct interaction with the NPCs, seeing the same named ship may provide impetus for the player to, say, defend the NPC from a pirate attack, whereas with a generic new NPC the player might just pass by…or attack the NPC themselves.
Another reason is because I want there to be a level of logic and realism involving what are the player’s “main competition”. If NPCs could teleport between stations, buying and selling, then they could quickly outstrip the player and potentially unbalance the economics by clearing the shelves or meeting commodity quotas before the player has a chance to reach those stations. Since the player is governed by time and relative distance, this puts the player at a severe disadvantage. Simulating the time it takes for a ship to move across several sectors, dock, buy and sell, and undock gives the player some padding to “get ahead” of NPCs. It also allows the player to follow an NPC. With the instantiation plan, a player should be able to tail a merchant to a gate, jump through, and see that NPC on the other side (with some creative license re: timings). They should be able to follow the NPC to their destination, and then see the NPC leave and start a new route. Would a player do this? Maybe they would, just to see if they could, but they could also decide that they want to scan an NPC that crosses their path, and might decide to engage in piracy of their own. In that case, having cargo matters, and knowing when we should and shouldn’t instantiate a specific NPC in the player’s sector also matters. Going a bit further, if the player could open comms with an NPC, maybe the NPC could offer the player an escort job (if the cargo is worth enough) as an ad hoc mission. None of these could happen in a pleasing manner using the current per-sector instantiation method I have in place right now.