Quote:
Originally Posted by CriticallyDev
Wish you the best of luck! Can't wait to try it out, this patch in my opinion was one of the best TQ had came out with. anything above 5017 just killed CO. xD
|
Quote:
Originally Posted by CriticallyDev
Wish you the best of luck! Can't wait to try it out, this patch in my opinion was one of the best TQ had came out with. anything above 5017 just killed CO. xD
|
Thanks for the interest
I really enjoy this patch level as well. I'm still aiming for a closed beta around September.
______________
Just want to tell you guys how I'm handling npc scripts
High level overview.
When the server loads up, using a plugin system it finds all classes that are inheriting from NpcScript and builds up a map[Int, NpcScript]. Once these have been loaded my npc actors pull in their related script. If no script is available it default to a singleton instance that simple sends a message containing the npcs id. Each time a npc actor receives a interaction request the script is ran asynchronously using a Future. I'm using this plugin system for item usage, mob ai's (for example, one for guards and another for mobs), event scheduling, etc.
Details
The core part of NpcScript is the @Response annotation. When a method defines this it will have a link id generated and be added to an internal data structure using reflection. When a message comes in, the method with the related link is called dynamically. I also added a method(name) function that looks up the link id of a method. I find explicitly hard coding the link ids all over ugly as fuck and makes it much harder to read.
The other optional core method is handleCallback(implicit cmd: ServerNpcCommand, client: ActorRef). This function is called when a internal message is sent to the npc. For example say an NPC is checking whether a character has a specific item in their inventory. The npc actor doesn't have direct access to the character actors state. In order to check if he has an item the npc can send a DoYouHaveItem(id) message and then the client actor will response with yes or no. This function will be called in those situations.
Below is how the Twin City conductress is implemented. I haven't added gold checks yet
Code:
/**
* Responsible for teleporting a character in TwinCity to different cities at a defined cost
* @see TCConductress#cost
*/
class TCConductress extends NpcScript {
lazy val market = RespawnPoints.respawnPoints.get(MapIDs.Market).get
lazy val ape = GamePortals.findPortal(MapIDs.ApeMoutain, MapIDs.TwinCity)
lazy val desert = GamePortals.findPortal(MapIDs.DesertCity, MapIDs.TwinCity)
lazy val bi = GamePortals.findPortal(MapIDs.BirdIsland, MapIDs.TwinCity)
lazy val pc = GamePortals.findPortal(MapIDs.PhoenixCastle, MapIDs.TwinCity)
val id = 10050
val cost = 100
override def handle(implicit event: NpcInteraction, client: ActorRef) {
method(event.linkID).invoke(this, event, client)
@ResponseInit
def init() {
Options(
"Welcome to the Twin City Conductress. Where would you like to go?",
"No thanks",
"Ape Mountain" -> method("toApe"),
"Bird Island" -> method("toBI"),
"Desert City" -> method("toDC"),
"Phoenix Castle" -> method("toPC"),
"Market" -> method("toMarket")
)
}
@Response
def toApe() =
sendToClient(TeleportTo(ape.toMap, ape.toX, ape.toY))
@Response
def toBI() =
sendToClient(TeleportTo(bi.toMap, bi.toX, bi.toY))
@Response
def toDC =
sendToClient(TeleportTo(desert.toMap, desert.toX, desert.toY))
@Response
def toPC =
sendToClient(TeleportTo(pc.toMap, pc.toX, pc.toY))
@Response
def toMarket =
sendToClient(TeleportTo(market.revivemapid, market.revivex, market.revivey))
}
}
Let me know what you guys think.
Also digital ocean is freaking amazing for remote testing. I can spin up an SSD VPS in seconds for an hour or so and only get charged about 5 cents. The server is running perfectly fine on a 2CPU/2GIG/40SSD Linux VPS.