diff --git a/ngengine_public.jar b/ngengine_public.jar index 0d2614d2..326b2a85 100644 Binary files a/ngengine_public.jar and b/ngengine_public.jar differ diff --git a/odb/guild/placeholder.txt b/odb/guild/placeholder.txt new file mode 100644 index 00000000..e69de29b diff --git a/scripts/commands/boardshuttle.py b/scripts/commands/boardshuttle.py new file mode 100644 index 00000000..013a0748 --- /dev/null +++ b/scripts/commands/boardshuttle.py @@ -0,0 +1,26 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + trvSvc = core.travelService + ticketList = trvSvc.getTicketList(actor) + print ('command called') + if ticketList.size() >= 1: + trvSvc.sendTicketWindow(actor) + return + + elif ticketList.size() == 1: + planetArrival = ticketList.get[0].getStringAttribute('@obj_attr_n:travel_arrival_planet') + locationArrival = ticketList.get[0].getStringAttribute('@obj_attr_n:travel_arrival_point') + tpArrival = trvSvc.getTravelPointByName(planet, location) + + trvSvc.doTransport(actor, tpArrival) + + return + elif ticketList.isEmpty == True: + actor.sendSystemMessage("You don't have a travel ticket for this shuttle.", 0) + return + #--tp = core.travelService.getTravelPointByName(travelTicket.getStringAttribute('@obj_attr_n:travel_arrival_point')) + return \ No newline at end of file diff --git a/scripts/demo.py b/scripts/demo.py index b2b49987..2b7889ee 100644 --- a/scripts/demo.py +++ b/scripts/demo.py @@ -12,12 +12,7 @@ def CreateStartingCharacter(core, object): testObject.setMaxDamage(1150) testObject.setElementalDamage(50) testObject.setIntAttribute('cat_wpn_damage.weapon_dps', testObject.getDamagePerSecond()) - object.addSkillMod('constitution_modified' , 350) - object.addSkillMod('strength_modified' , 350) - object.addSkillMod('precision_modified' , 350) - object.addSkillMod('luck_modified' , 350) - object.addSkillMod('agility_modified' , 350) - object.addSkillMod('stamina_modified' , 350) + testObject.setIntAttribute('cat_skill_mod_bonus.@stat_n:precision_modified', 35) object.addSkillMod('kinetic' , 10000) object.addSkillMod('energy' , 10000) object.addSkillMod('heat' , 6000) diff --git a/scripts/object/building/tatooine/starport_tatooine.py b/scripts/object/building/tatooine/starport_tatooine.py index 0200b779..34468ac1 100644 --- a/scripts/object/building/tatooine/starport_tatooine.py +++ b/scripts/object/building/tatooine/starport_tatooine.py @@ -9,8 +9,6 @@ def setup(core, object): stcSvc.spawnObject('object/tangible/terminal/shared_terminal_travel.iff', object.getPlanet().getName(), cell.getObjectID(), float(3.1), float(0.6), float(49), float(0), float(1)) stcSvc.spawnObject('object/tangible/terminal/shared_terminal_travel.iff', object.getPlanet().getName(), cell.getObjectID(), float(-2.7), float(0.6), float(49), float(0), float(1)) stcSvc.spawnObject('object/tangible/terminal/shared_terminal_travel.iff', object.getPlanet().getName(), cell.getObjectID(), float(-13.2), float(0.6), float(51.3), float(-0.195405), float(-0.980722)) - core.mapService.addLocation(object.getPlanet(), 'Starport', object.getPosition().x, object.getPosition().z, 15, 0, 0) - #core.travelService.addTravelPoint(object.getPlanet(), ) return \ No newline at end of file diff --git a/scripts/object/creature/npc/theme_park/player_transport.py b/scripts/object/creature/npc/theme_park/player_transport.py index ccad8904..1e3efb77 100644 --- a/scripts/object/creature/npc/theme_park/player_transport.py +++ b/scripts/object/creature/npc/theme_park/player_transport.py @@ -1,4 +1,7 @@ import sys def setup(core, object): + object.setPosture(0) # land = 0 : away = 2 + object.setOptionsBitmask(256) + core.travelService.addShuttleToPoint(object) return \ No newline at end of file diff --git a/scripts/object/tangible/terminal/terminal_travel.py b/scripts/object/tangible/terminal/terminal_travel.py index ccad8904..160aac1c 100644 --- a/scripts/object/tangible/terminal/terminal_travel.py +++ b/scripts/object/tangible/terminal/terminal_travel.py @@ -1,4 +1,5 @@ import sys def setup(core, object): + object.setAttachment('radial_filename', 'travel_terminal') return \ No newline at end of file diff --git a/scripts/object/tangible/travel/ticket_collector/ticket_collector.py b/scripts/object/tangible/travel/ticket_collector/ticket_collector.py index ccad8904..d243308d 100644 --- a/scripts/object/tangible/travel/ticket_collector/ticket_collector.py +++ b/scripts/object/tangible/travel/ticket_collector/ticket_collector.py @@ -1,4 +1,5 @@ import sys def setup(core, object): + object.setAttachment('radial_filename', 'npc_ticket_collector') return \ No newline at end of file diff --git a/scripts/radial/npc_ticket_collector.py b/scripts/radial/npc_ticket_collector.py new file mode 100644 index 00000000..1cc0cc1c --- /dev/null +++ b/scripts/radial/npc_ticket_collector.py @@ -0,0 +1,17 @@ +from resources.common import RadialOptions +import sys + +def createRadial(core, owner, target, radials): + return + +def handleSelection(core, owner, target, option): + trvSvc = core.travelService + if option == 21 and target: + core.commandService.callCommand(owner, 'boardshuttle', target, '') + print ('command called') + return + return + +def handleSUI(owner, window, eventType, returnList): + + return \ No newline at end of file diff --git a/scripts/radial/travel_terminal.py b/scripts/radial/travel_terminal.py new file mode 100644 index 00000000..934e0f92 --- /dev/null +++ b/scripts/radial/travel_terminal.py @@ -0,0 +1,19 @@ +from resources.common import RadialOptions +from protocol.swg import EnterTicketPurchaseModeMessage +import sys + +def createRadial(core, owner, target, radials): + return + +def handleSelection(core, owner, target, option): + + if option == 21 and target: + tpm = EnterTicketPurchaseModeMessage(owner.getPlanet().getName(), core.mapService.getClosestCityName(owner)) + owner.getClient().getSession().write(tpm.serialize()) + #print ('Planet name: ' + owner.getPlanet().getName()) + #print ('City name: ' + core.mapService.getClosestCityName(owner)) + return + +def handleSUI(owner, window, eventType, returnList): + + return \ No newline at end of file diff --git a/scripts/roadmap/bothan.py b/scripts/roadmap/bothan.py new file mode 100644 index 00000000..ffa89ff7 --- /dev/null +++ b/scripts/roadmap/bothan.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 60 + +def getPrecision(): + return 65 + +def getStrength(): + return 0 + +def getConstitution(): + return 25 + +def getStamina(): + return 0 + +def getAgility(): + return 50 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/bounty_hunter_1a.py b/scripts/roadmap/bounty_hunter_1a.py new file mode 100644 index 00000000..7bb425e3 --- /dev/null +++ b/scripts/roadmap/bounty_hunter_1a.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 20 + +def getPrecision(): + return 60 + +def getStrength(): + return 40 + +def getConstitution(): + return 80 + +def getStamina(): + return 80 + +def getAgility(): + return 80 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/commando_1a.py b/scripts/roadmap/commando_1a.py new file mode 100644 index 00000000..8d9253ae --- /dev/null +++ b/scripts/roadmap/commando_1a.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 60 + +def getPrecision(): + return 120 + +def getStrength(): + return 120 + +def getConstitution(): + return 60 + +def getStamina(): + return 0 + +def getAgility(): + return 0 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/entertainer_1a.py b/scripts/roadmap/entertainer_1a.py new file mode 100644 index 00000000..0541cc93 --- /dev/null +++ b/scripts/roadmap/entertainer_1a.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 80 + +def getPrecision(): + return 0 + +def getStrength(): + return 0 + +def getConstitution(): + return 40 + +def getStamina(): + return 120 + +def getAgility(): + return 120 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/force_sensitive_1a.py b/scripts/roadmap/force_sensitive_1a.py new file mode 100644 index 00000000..2d9241b0 --- /dev/null +++ b/scripts/roadmap/force_sensitive_1a.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 30 + +def getPrecision(): + return 30 + +def getStrength(): + return 100 + +def getConstitution(): + return 40 + +def getStamina(): + return 40 + +def getAgility(): + return 120 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/human.py b/scripts/roadmap/human.py new file mode 100644 index 00000000..8bda8fd7 --- /dev/null +++ b/scripts/roadmap/human.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 0 + +def getPrecision(): + return 50 + +def getStrength(): + return 50 + +def getConstitution(): + return 0 + +def getStamina(): + return 50 + +def getAgility(): + return 50 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/ithorian.py b/scripts/roadmap/ithorian.py new file mode 100644 index 00000000..7d0c2b34 --- /dev/null +++ b/scripts/roadmap/ithorian.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 30 + +def getPrecision(): + return 40 + +def getStrength(): + return 60 + +def getConstitution(): + return 0 + +def getStamina(): + return 70 + +def getAgility(): + return 0 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/medic_1a.py b/scripts/roadmap/medic_1a.py new file mode 100644 index 00000000..6b84327b --- /dev/null +++ b/scripts/roadmap/medic_1a.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 80 + +def getPrecision(): + return 50 + +def getStrength(): + return 50 + +def getConstitution(): + return 60 + +def getStamina(): + return 120 + +def getAgility(): + return 0 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/moncalamari.py b/scripts/roadmap/moncalamari.py new file mode 100644 index 00000000..83d0d04c --- /dev/null +++ b/scripts/roadmap/moncalamari.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 40 + +def getPrecision(): + return 60 + +def getStrength(): + return 0 + +def getConstitution(): + return 40 + +def getStamina(): + return 60 + +def getAgility(): + return 0 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/roadmap_rewards.py b/scripts/roadmap/roadmap_rewards.py new file mode 100644 index 00000000..2f11d77e --- /dev/null +++ b/scripts/roadmap/roadmap_rewards.py @@ -0,0 +1,4 @@ +import sys + +def get(name): + return "" diff --git a/scripts/roadmap/rodian.py b/scripts/roadmap/rodian.py new file mode 100644 index 00000000..9187fd12 --- /dev/null +++ b/scripts/roadmap/rodian.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 20 + +def getPrecision(): + return 80 + +def getStrength(): + return 0 + +def getConstitution(): + return 0 + +def getStamina(): + return 20 + +def getAgility(): + return 80 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/smuggler_1a.py b/scripts/roadmap/smuggler_1a.py new file mode 100644 index 00000000..8084fcd2 --- /dev/null +++ b/scripts/roadmap/smuggler_1a.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 120 + +def getPrecision(): + return 20 + +def getStrength(): + return 20 + +def getConstitution(): + return 70 + +def getStamina(): + return 30 + +def getAgility(): + return 100 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/spy_1a.py b/scripts/roadmap/spy_1a.py new file mode 100644 index 00000000..6fe7c37a --- /dev/null +++ b/scripts/roadmap/spy_1a.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 40 + +def getPrecision(): + return 50 + +def getStrength(): + return 50 + +def getConstitution(): + return 80 + +def getStamina(): + return 40 + +def getAgility(): + return 100 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/sullustan.py b/scripts/roadmap/sullustan.py new file mode 100644 index 00000000..c02f8dcc --- /dev/null +++ b/scripts/roadmap/sullustan.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 40 + +def getPrecision(): + return 0 + +def getStrength(): + return 40 + +def getConstitution(): + return 60 + +def getStamina(): + return 0 + +def getAgility(): + return 60 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/trader_0a.py b/scripts/roadmap/trader_0a.py new file mode 100644 index 00000000..2846dee7 --- /dev/null +++ b/scripts/roadmap/trader_0a.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 90 + +def getPrecision(): + return 140 + +def getStrength(): + return 140 + +def getConstitution(): + return 0 + +def getStamina(): + return 50 + +def getAgility(): + return 140 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/trader_0b.py b/scripts/roadmap/trader_0b.py new file mode 100644 index 00000000..2846dee7 --- /dev/null +++ b/scripts/roadmap/trader_0b.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 90 + +def getPrecision(): + return 140 + +def getStrength(): + return 140 + +def getConstitution(): + return 0 + +def getStamina(): + return 50 + +def getAgility(): + return 140 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/trader_0c.py b/scripts/roadmap/trader_0c.py new file mode 100644 index 00000000..2846dee7 --- /dev/null +++ b/scripts/roadmap/trader_0c.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 90 + +def getPrecision(): + return 140 + +def getStrength(): + return 140 + +def getConstitution(): + return 0 + +def getStamina(): + return 50 + +def getAgility(): + return 140 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/trader_0d.py b/scripts/roadmap/trader_0d.py new file mode 100644 index 00000000..2846dee7 --- /dev/null +++ b/scripts/roadmap/trader_0d.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 90 + +def getPrecision(): + return 140 + +def getStrength(): + return 140 + +def getConstitution(): + return 0 + +def getStamina(): + return 50 + +def getAgility(): + return 140 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/trandoshan.py b/scripts/roadmap/trandoshan.py new file mode 100644 index 00000000..6bc9697e --- /dev/null +++ b/scripts/roadmap/trandoshan.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 0 + +def getPrecision(): + return 0 + +def getStrength(): + return 50 + +def getConstitution(): + return 65 + +def getStamina(): + return 65 + +def getAgility(): + return 20 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/twilek.py b/scripts/roadmap/twilek.py new file mode 100644 index 00000000..41903237 --- /dev/null +++ b/scripts/roadmap/twilek.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 40 + +def getPrecision(): + return 40 + +def getStrength(): + return 0 + +def getConstitution(): + return 0 + +def getStamina(): + return 60 + +def getAgility(): + return 60 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/wookiee.py b/scripts/roadmap/wookiee.py new file mode 100644 index 00000000..3fe24070 --- /dev/null +++ b/scripts/roadmap/wookiee.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 0 + +def getPrecision(): + return 10 + +def getStrength(): + return 85 + +def getConstitution(): + return 85 + +def getStamina(): + return 40 + +def getAgility(): + return 0 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/roadmap/zabrak.py b/scripts/roadmap/zabrak.py new file mode 100644 index 00000000..6e8226de --- /dev/null +++ b/scripts/roadmap/zabrak.py @@ -0,0 +1,25 @@ +import sys + +def getLuck(): + return 0 + +def getPrecision(): + return 50 + +def getStrength(): + return 50 + +def getConstitution(): + return 50 + +def getStamina(): + return 0 + +def getAgility(): + return 50 + +def getHealth(): + return 100 + +def getAction(): + return 75 diff --git a/scripts/static_spawns/tatooine.py b/scripts/static_spawns/tatooine.py index 4b3981c7..3f166add 100644 --- a/scripts/static_spawns/tatooine.py +++ b/scripts/static_spawns/tatooine.py @@ -10,6 +10,9 @@ def addPlanetSpawns(core, planet): stcSvc.spawnObject('object/tangible/travel/ticket_collector/shared_ticket_collector.iff', 'tatooine', long(0), float(-1382.15), float(12), float(-3583.25), float(1), float(-0.08)) # bestine starport stcSvc.spawnObject('object/tangible/travel/ticket_collector/shared_ticket_collector.iff', 'tatooine', long(0), float(3427.5), float(5.6), float(-4644.1), float(-0.485545), float(0.874212)) # mos eisley shuttleport stcSvc.spawnObject('object/tangible/travel/ticket_collector/shared_ticket_collector.iff', 'tatooine', long(0), float(3623.5), float(5), float(-4793.5), float(-0.103924), float(0.994585)) # mos eisley starport + + stcSvc.spawnObject('object/creature/npc/theme_park/shared_player_transport.iff', 'tatooine', long(0), float(3619), float(5), float(-4801), float(-0.103924), float(0)) # mos eisley starport + stcSvc.spawnObject('object/tangible/travel/ticket_collector/shared_ticket_collector.iff', 'tatooine', long(0), float(-2886.3), float(5.6), float(1929.4), float(-0.113814), float(0.993502)) # mos espa shuttleport a stcSvc.spawnObject('object/tangible/travel/ticket_collector/shared_ticket_collector.iff', 'tatooine', long(0), float(-3116.3), float(5.6), float(2166.1), float(-0.621933), float(0.783071)) # mos espa shuttleport b stcSvc.spawnObject('object/tangible/travel/ticket_collector/shared_ticket_collector.iff', 'tatooine', long(0), float(3623.5), float(5.6), float(2178.4), float(-0.123692), float(0.992321)) # mos espa shuttleport c @@ -19,7 +22,6 @@ def addPlanetSpawns(core, planet): stcSvc.spawnObject('object/tangible/travel/ticket_collector/shared_ticket_collector.iff', 'tatooine', long(0), float(1721.5), float(7.6), float(3191.3), float(1), float(0)) # mos entha shuttleport b stcSvc.spawnObject('object/tangible/travel/ticket_collector/shared_ticket_collector.iff', 'tatooine', long(0), float(-2820.5), float(5), float(2083.71), float(0), float(1)) # mos espa starport - stcSvc.spawnObject('object/tangible/terminal/shared_terminal_travel.iff', 'tatooine', long(0), float(-1091.9), float(12.6), float(-3572.7), float(-0.645025), float(0.764162)) # bestine shuttleport stcSvc.spawnObject('object/tangible/terminal/shared_terminal_travel.iff', 'tatooine', long(0), float(-2903.5), float(5.6), float(1924), float(-0.113814), float(0.993502)) # mos espa shuttleport a diff --git a/scripts/static_travel_points.py b/scripts/static_travel_points.py index 58baf244..e6d0987b 100644 --- a/scripts/static_travel_points.py +++ b/scripts/static_travel_points.py @@ -2,16 +2,102 @@ import sys def addPoints(core, planet): + if planet.getName() == 'corellia': + corelliaPoints(core, planet) + if planet.getName() == 'dantooine': + dantooinePoints(core, planet) + if planet.getName() == 'dathomir': + dathomirPoints(core, planet) + if planet.getName() == 'endor': + endorPoints(core, planet) + if planet.getName() == 'lok': + lokPoints(core, planet) + if planet.getName() == 'naboo': + nabooPoints(core, planet) + if planet.getName() == 'rori': + roriPoints(core, planet) + if planet.getName() == 'talus': + talusPoints(core, planet) if planet.getName() == 'tatooine': tatooinePoints(core, planet) - + if planet.getName() == 'yavin4': + yavin4Points(core, planet) return - + +def corelliaPoints(core, planet): + trvSvc = core.travelService + + trvSvc.addTravelPoint(planet, "Coronet Starport", -51, 28, -4735) + trvSvc.addTravelPoint(planet, "Tyrena Starport", -4975, 21, -2230) + trvSvc.addTravelPoint(planet, "Kor Vella Starport", -3136, 31, 2894) + trvSvc.addTravelPoint(planet, "Doaba Guerful Starport", 3377, 308, 5605) + return + +def dantooinePoints(core, planet): + trvSvc = core.travelService + + trvSvc.addTravelPoint(planet, "Coronet Starport", -51, 28, -4735) + trvSvc.addTravelPoint(planet, "Tyrena Starport", -4975, 21, -2230) + trvSvc.addTravelPoint(planet, "Kor Vella Starport", -3136, 31, 2894) + trvSvc.addTravelPoint(planet, "Doaba Guerful Starport", 3377, 308, 5605) + return + +def dathomirPoints(core, planet): + trvSvc = core.travelService + + trvSvc.addTravelPoint(planet, "Science Outpost", -76, 18, -1586) + trvSvc.addTravelPoint(planet, "Trade Outpost", -592, 6, 3087) + return + +def endorPoints(core, planet): + trvSvc = core.travelService + + trvSvc.addTravelPoint(planet, "Smuggler Outpost", -978, 73, 1554) + trvSvc.addTravelPoint(planet, "Research Outpost", 3222, 24, -3482) + return + +def lokPoints(core, planet): + trvSvc = core.travelService + + trvSvc.addTravelPoint(planet, "Nym's Stronghold", 459, 9, 5494) + return + +def nabooPoints(core, planet): + trvSvc = core.travelService + + trvSvc.addTravelPoint(planet, "Kaadara Starport", 5295, -192, 6664) + trvSvc.addTravelPoint(planet, "Keren Starport", 1352, 13, 2768) + trvSvc.addTravelPoint(planet, "Moenia Starport", 4728, 4, -4650) + return + +def roriPoints(core, planet): + trvSvc = core.travelService + + trvSvc.addTravelPoint(planet, "Narmle Starport", -5472, 80, 2161) + trvSvc.addTravelPoint(planet, "Rebel Outpost", 3672, 96, -6421) + return + +def talusPoints(core, planet): + trvSvc = core.travelService + + trvSvc.addTravelPoint(planet, "Dearic Starport", 245, 6, -2931) + trvSvc.addTravelPoint(planet, "Nashal Starport", 4480, 2, 6365) + trvSvc.addTravelPoint(planet, "Imperial Outpost", -2212, 20, 2302) + return + def tatooinePoints(core, planet): trvSvc = core.travelService - trvSvc.addTravelPoint("tatooine", "Bestine Starport", -1376, 12, -3576) - trvSvc.addTravelPoint("tatooine", "Mos Eisley Starport", 3619, 5, -4801) - trvSvc.addTravelPoint("tatooine", "Mos Espa Starport", -2829, 5, 2080) - trvSvc.addTravelPoint("tatooine", "Mos Entha Starport", 1238, 7, 3062) + trvSvc.addTravelPoint(planet, "Bestine Starport", -1376, 12, -3576) + trvSvc.addTravelPoint(planet, "Mos Eisley Starport", 3619, 5, -4801) + trvSvc.addTravelPoint(planet, "Mos Espa Starport", -2829, 5, 2080) + trvSvc.addTravelPoint(planet, "Mos Entha Starport", 1238, 7, 3062) + return + +def yavin4Points(core, planet): + trvSvc = core.travelService + + trvSvc.addTravelPoint(planet, "Imperial Base", 4033, 37, -6234) + trvSvc.addTravelPoint(planet, "Labor Outpost", -6939, 73, -5706) + trvSvc.addTravelPoint(planet, "Mining Outpost", -277, 35, 4879) return \ No newline at end of file diff --git a/src/main/NGECore.java b/src/main/NGECore.java index 0ebb0880..fcf2ed76 100644 --- a/src/main/NGECore.java +++ b/src/main/NGECore.java @@ -31,18 +31,23 @@ import java.util.concurrent.ConcurrentHashMap; + + import resources.common.RadialOptions; +import resources.common.ThreadMonitor; import resources.objects.creature.CreatureObject; import services.AttributeService; import services.BuffService; import services.CharacterService; import services.ConnectionService; +import services.EquipmentService; import services.GroupService; import services.LoginService; import services.PlayerService; import services.ScriptService; import services.SimulationService; import services.SkillModService; +import services.SkillService; import services.StaticService; import services.TerrainService; import services.chat.ChatService; @@ -56,6 +61,7 @@ import services.object.ObjectService; import services.object.UpdateService; import services.sui.SUIService; import services.trade.TradeService; +import services.travel.TravelService; import engine.clientdata.ClientFileManager; import engine.clientdata.visitors.CrcStringTableVisitor; import engine.clientdata.visitors.DatatableVisitor; @@ -119,7 +125,10 @@ public class NGECore { public BuffService buffService; public StaticService staticService; public GroupService groupService; + public SkillService skillService; public SkillModService skillModService; + public EquipmentService equipmentService; + public TravelService travelService; // Login Server public NetworkDispatch loginDispatch; @@ -139,12 +148,25 @@ public class NGECore { public void start() { instance = this; + + final ThreadMonitor deadlockDetector = new ThreadMonitor(); + Thread deadlockMonitor = new Thread(new Runnable() { + @Override + public void run() { + try { + deadlockDetector.findDeadlock(); + Thread.sleep(60000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }); + deadlockMonitor.start(); config = new Config(); config.setFilePath("nge.cfg"); if (!(config.loadConfigFile())) { config = DefaultConfig.getConfig(); } - // Database databaseConnection = new DatabaseConnection(); databaseConnection.connect(config.getString("DB.URL"), config.getString("DB.NAME"), config.getString("DB.USER"), config.getString("DB.PASS"), "postgresql"); @@ -159,6 +181,7 @@ public class NGECore { connectionService = new ConnectionService(this); characterService = new CharacterService(this); mapService = new MapService(this); + travelService = new TravelService(this); objectService = new ObjectService(this); terrainService = new TerrainService(this); @@ -172,7 +195,10 @@ public class NGECore { playerService = new PlayerService(this); buffService = new BuffService(this); groupService = new GroupService(this); + skillService = new SkillService(this); skillModService = new SkillModService(this); + equipmentService = new EquipmentService(this); + // Ping Server try { @@ -198,6 +224,7 @@ public class NGECore { zoneDispatch.addService(chatService); zoneDispatch.addService(suiService); zoneDispatch.addService(mapService); + zoneDispatch.addService(travelService); zoneDispatch.addService(playerService); zoneServer = new MINAServer(zoneDispatch, config.getInt("ZONE.PORT")); @@ -215,18 +242,20 @@ public class NGECore { terrainService.addPlanet(8, "yavin4", "terrain/yavin4.trn", true); terrainService.addPlanet(9, "endor", "terrain/endor.trn", true); terrainService.addPlanet(10, "dathomir", "terrain/dathomir.trn", true); + terrainService.addPlanet(11, "mustafar", "terrain/mustafar.trn", true); + terrainService.addPlanet(12, "kashyyyk_main", "terrain/kashyyyk_main.trn", true); terrainService.loadSnapShotObjects(); - - // Zone services that need to be loaded after the above simulationService = new SimulationService(this); zoneDispatch.addService(simulationService); + // Travel Points + travelService.loadTravelPoints(); + // Static Spawns staticService.spawnStatics(); - guildService = new GuildService(this); zoneDispatch.addService(guildService); @@ -236,6 +265,8 @@ public class NGECore { tradeService = new TradeService(this); zoneDispatch.addService(tradeService); + zoneDispatch.addService(skillService); + didServerCrash = false; System.out.println("Started Server."); setGalaxyStatus(2); diff --git a/src/protocol/swg/ChatSystemMessage.java b/src/protocol/swg/ChatSystemMessage.java index 0c973ad4..e12aa1f4 100644 --- a/src/protocol/swg/ChatSystemMessage.java +++ b/src/protocol/swg/ChatSystemMessage.java @@ -25,16 +25,26 @@ import java.nio.ByteOrder; import org.apache.mina.core.buffer.IoBuffer; -public class ChatSystemMessage extends SWGMessage{ +import resources.common.Opcodes; +public class ChatSystemMessage extends SWGMessage{ + + private String stfFilename; + private String stfName; + private int stat; private String message; private byte displayType; - + public ChatSystemMessage(String message, byte displayType) { - this.message = message; this.displayType = displayType; - + } + + public ChatSystemMessage(String stfFilename, String stfName, int stat, byte displayType) { + this.stfFilename = stfFilename; + this.stfName = stfName; + this.stat = stat; + this.displayType = displayType; } public void deserialize(IoBuffer data) { @@ -42,18 +52,40 @@ public class ChatSystemMessage extends SWGMessage{ } public IoBuffer serialize() { - - IoBuffer result = IoBuffer.allocate(15 + message.length() * 2).order(ByteOrder.LITTLE_ENDIAN); - - result.putShort((short) 2); - result.putInt(0x6D2A6413); - - result.put(displayType); // 0x00 = Chat and Screen // 0x02 = Chat only - result.put(getUnicodeString(message)); - result.putInt(0); // unk - - return result.flip(); - + if (message != null) { + IoBuffer result = IoBuffer.allocate(15 + message.length() * 2).order(ByteOrder.LITTLE_ENDIAN); + result.putShort((short) 2); + result.putInt(Opcodes.ChatSystemMessage); + result.put(displayType); // 0x00 = Chat and Screen // 0x02 = Chat only + result.put(getUnicodeString(message)); + result.putInt(0); + return result.flip(); + } else { + IoBuffer result = IoBuffer.allocate(99 + stfFilename.length() + stfName.length()).order(ByteOrder.LITTLE_ENDIAN); + result.putShort((short) 4); + result.putInt(Opcodes.ChatSystemMessage); + result.put((byte) 0); //result.put((byte) displayType); // 0x00 = Chat and Screen // 0x02 = Chat only + result.putInt(0); + result.putInt(54); + result.putShort((short) 0); + result.put((byte) 1); + result.putInt(-1); + result.put(getAsciiString(stfFilename)); + result.putInt(0); + result.put(getAsciiString(stfName)); + result.putInt(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putInt(stat); + result.putInt(0); + result.put((byte) 0); + return result.flip(); + } } - + } diff --git a/src/protocol/swg/ClientMfdStatusUpdateMessage.java b/src/protocol/swg/ClientMfdStatusUpdateMessage.java new file mode 100644 index 00000000..98330d77 --- /dev/null +++ b/src/protocol/swg/ClientMfdStatusUpdateMessage.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2013 + * + * This File is part of NGECore2. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Using NGEngine to work with NGECore2 is making a combined work based on NGEngine. + * Therefore all terms and conditions of the GNU Lesser General Public License cover the combination. + ******************************************************************************/ +package protocol.swg; + +import java.nio.ByteOrder; + +import org.apache.mina.core.buffer.IoBuffer; + +import resources.common.Opcodes; + +public class ClientMfdStatusUpdateMessage extends SWGMessage { + + private float mfdStatus; + private String mfdSetting; + + public ClientMfdStatusUpdateMessage(float mfdStatus, String mfdSetting) { + this.mfdStatus = mfdStatus; + this.mfdSetting = mfdSetting; + } + + @Override + public IoBuffer serialize() { + IoBuffer result = IoBuffer.allocate(12 + mfdSetting.length()).order(ByteOrder.LITTLE_ENDIAN); + result.putShort((short) 3); + result.putInt(Opcodes.ClientMfdStatusUpdateMessage); + result.putFloat(mfdStatus); + result.put(getAsciiString(mfdSetting)); + return result.flip(); + } + + @Override + public void deserialize(IoBuffer data) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/protocol/swg/EnterTicketPurchaseModeMessage.java b/src/protocol/swg/EnterTicketPurchaseModeMessage.java new file mode 100644 index 00000000..2c5c2315 --- /dev/null +++ b/src/protocol/swg/EnterTicketPurchaseModeMessage.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2013 + * + * This File is part of NGECore2. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Using NGEngine to work with NGECore2 is making a combined work based on NGEngine. + * Therefore all terms and conditions of the GNU Lesser General Public License cover the combination. + ******************************************************************************/ +package protocol.swg; + +import java.nio.ByteOrder; + +import org.apache.mina.core.buffer.IoBuffer; + +public class EnterTicketPurchaseModeMessage extends SWGMessage { + + public String planetName; + public String cityName; + + public EnterTicketPurchaseModeMessage(String planetName, String cityName) { + this.planetName = planetName; + this.cityName = cityName; + } + + @Override + public void deserialize(IoBuffer data) { + // TODO Auto-generated method stub + + } + + @Override + public IoBuffer serialize() { + IoBuffer result = IoBuffer.allocate(100).order(ByteOrder.LITTLE_ENDIAN); + + result.putShort((short) 3); + result.putInt(0x904DAE1A); + + result.put(getAsciiString(planetName)); + result.put(getAsciiString(cityName + " Starport")); + + return result.flip(); + } + +} diff --git a/src/protocol/swg/PlanetTravelPointListRequest.java b/src/protocol/swg/PlanetTravelPointListRequest.java index c47fffb6..51e37548 100644 --- a/src/protocol/swg/PlanetTravelPointListRequest.java +++ b/src/protocol/swg/PlanetTravelPointListRequest.java @@ -21,6 +21,8 @@ ******************************************************************************/ package protocol.swg; +import java.util.List; + import main.NGECore; import org.apache.mina.core.buffer.IoBuffer; @@ -31,17 +33,19 @@ public class PlanetTravelPointListRequest extends SWGMessage{ private NGECore core; private long objectId; - private Planet planet; + private String planet; @Override public void deserialize(IoBuffer buffer) { - buffer.getShort(); - buffer.getInt(); + //buffer.getShort(); + //buffer.getInt(); setObjectId(buffer.getLong()); setPlanet(getAsciiString(buffer)); + //System.out.println("String: " + getAsciiString(buffer)); + } @Override @@ -57,13 +61,11 @@ public class PlanetTravelPointListRequest extends SWGMessage{ this.objectId = objectId; } - public Planet getPlanet() { + public String getPlanet() { return planet; } public void setPlanet(String asciiString) { - Planet planet = core.terrainService.getPlanetByName(asciiString); - this.planet = planet; + this.planet = asciiString; } - } diff --git a/src/protocol/swg/PlanetTravelPointListResponse.java b/src/protocol/swg/PlanetTravelPointListResponse.java index 414a52ff..029b5f2f 100644 --- a/src/protocol/swg/PlanetTravelPointListResponse.java +++ b/src/protocol/swg/PlanetTravelPointListResponse.java @@ -22,6 +22,7 @@ package protocol.swg; import java.nio.ByteOrder; +import java.util.List; import java.util.Vector; import main.NGECore; @@ -34,12 +35,14 @@ import engine.resources.scene.Planet; @SuppressWarnings("unused") public class PlanetTravelPointListResponse extends SWGMessage { - private NGECore core; - private Planet originatePlanet; + private String planetString; private Vector travelPoints; + private List planetList; - public PlanetTravelPointListResponse(Planet planet, Vector travelPoints) { - this.originatePlanet = planet; + public PlanetTravelPointListResponse(String planetString, Vector travelPoints, List planetList) { + this.planetString = planetString; + this.travelPoints = travelPoints; + this.planetList = planetList; } @Override @@ -49,13 +52,12 @@ public class PlanetTravelPointListResponse extends SWGMessage { @Override public IoBuffer serialize() { - IoBuffer result = IoBuffer.allocate(100).order(ByteOrder.LITTLE_ENDIAN); + IoBuffer result = IoBuffer.allocate(700).order(ByteOrder.LITTLE_ENDIAN); - result.putShort((short) 9); + result.putShort((short) 6); result.putInt(0x4D32541F); - result.put(getAsciiString(originatePlanet.getName())); - result.putInt(core.terrainService.getPlanetList().size()); + result.put(getAsciiString(planetString)); result.putInt(travelPoints.size()); // shuttles/sp count for (TravelPoint point : travelPoints) { @@ -65,21 +67,19 @@ public class PlanetTravelPointListResponse extends SWGMessage { result.putInt(travelPoints.size()); // shuttles/sp count for (TravelPoint point : travelPoints) { - result.putFloat(point.getPosX()); - result.putFloat(point.getPosZ()); // Z and Y may be switched - result.putFloat(point.getPosY()); + result.putFloat(point.getLocation().x); + result.putFloat(0); + result.putFloat(point.getLocation().z); } result.putInt(travelPoints.size()); // shuttes/sp count for (TravelPoint point : travelPoints) { - // TODO: Change ticket price based on planet/distance result.putInt(point.getTicketPrice()); } result.putInt(travelPoints.size()); for (TravelPoint point : travelPoints) { - // TODO: Change based on planet/distance result.put((byte) 1); // isReachable } result.flip(); diff --git a/src/protocol/swg/PlayMusicMessage.java b/src/protocol/swg/PlayMusicMessage.java new file mode 100644 index 00000000..e2346f94 --- /dev/null +++ b/src/protocol/swg/PlayMusicMessage.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2013 + * + * This File is part of NGECore2. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Using NGEngine to work with NGECore2 is making a combined work based on NGEngine. + * Therefore all terms and conditions of the GNU Lesser General Public License cover the combination. + ******************************************************************************/ +package protocol.swg; + +import java.nio.ByteOrder; + +import org.apache.mina.core.buffer.IoBuffer; + +import resources.common.Opcodes; + +public class PlayMusicMessage extends SWGMessage { + + private long targetId; + private String sndFile; + private int repetitions; + private boolean flag; + + public PlayMusicMessage(String sndFile, long targetId, int repetitions, boolean flag) { + this.targetId = targetId; + this.sndFile = sndFile; + this.repetitions = repetitions; + this.flag = flag; + } + + @Override + public IoBuffer serialize() { + IoBuffer result = IoBuffer.allocate(21 + sndFile.length()).order(ByteOrder.LITTLE_ENDIAN); + result.putShort((short) 5); + result.putInt(Opcodes.PlayMusicMessage); + result.put(getAsciiString(sndFile)); + result.putLong(targetId); + result.putInt(repetitions); + result.put((byte) ((flag) ? 1 : 0)); + return result.flip(); + } + + @Override + public void deserialize(IoBuffer data) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/protocol/swg/objectControllerObjects/ShowFlyText.java b/src/protocol/swg/objectControllerObjects/ShowFlyText.java index 083d97b2..b4f73d31 100644 --- a/src/protocol/swg/objectControllerObjects/ShowFlyText.java +++ b/src/protocol/swg/objectControllerObjects/ShowFlyText.java @@ -26,53 +26,103 @@ import java.nio.ByteOrder; import org.apache.mina.core.buffer.IoBuffer; import protocol.swg.ObjControllerMessage; +import resources.common.RGB; public class ShowFlyText extends ObjControllerObject { private long recieverId; private long objectId; + private int unknownInt1; + private short unknownShort1; + private byte unknownByte1; + private int unknownInt2; private String stfFile; private String stfString; + private short unknownShort2; private float scale; - private float color; - - public ShowFlyText(long recieverId, long objectId, String stfFile, String stfString, float scale, float color) { + private RGB color; + private int displayType; + private boolean alternativeStructure; + + public ShowFlyText(long recieverId, long objectId, String stfFile, String stfString, float scale, RGB color, int displayType) { this.recieverId = recieverId; this.objectId = objectId; this.stfFile = stfFile; this.stfString = stfString; this.scale = scale; this.color = color; + this.displayType = displayType; + this.alternativeStructure = false; } - + + public ShowFlyText(long recieverId, long objectId, int unknownInt1, int unknownShort1, int unknownByte1, int unknownInt2, String stfFile, String stfString, int unknownShort2, float scale, RGB color, int displayType) { + this.recieverId = recieverId; + this.objectId = objectId; + this.unknownInt1 = unknownInt1; + this.unknownShort1 = (short) unknownShort1; + this.unknownByte1 = (byte) unknownByte1; + this.unknownInt2 = unknownInt2; + this.stfFile = stfFile; + this.stfString = stfString; + this.unknownShort2 = (short) unknownShort2; + this.scale = scale; + this.color = color; + this.alternativeStructure = true; + } + @Override public void deserialize(IoBuffer data) { // TODO Auto-generated method stub } - + @Override - public IoBuffer serialize() { - - IoBuffer result = IoBuffer.allocate(47 + stfFile.length() + stfString.length()).order(ByteOrder.LITTLE_ENDIAN); - result.setAutoExpand(true); - - result.putInt(ObjControllerMessage.SHOW_FLY_TEXT); - result.putLong(recieverId); - result.putInt(0); - result.putLong(objectId); - - result.put(getAsciiString(stfFile)); - result.putInt(0); - result.put(getAsciiString(stfString)); - result.putInt(0); - result.putFloat(scale); - result.putFloat(color); // color - result.putShort((short) 0); - result.put((byte) 0); - - return result.flip(); - + public IoBuffer serialize() { + if (!alternativeStructure) { + IoBuffer result = IoBuffer.allocate(47 + stfFile.length() + stfString.length()).order(ByteOrder.LITTLE_ENDIAN); + result.setAutoExpand(true); + result.putInt(ObjControllerMessage.SHOW_FLY_TEXT); + result.putLong(recieverId); + result.putInt(0); + result.putLong(objectId); + result.put(getAsciiString(stfFile)); + result.putInt(0); + result.put(getAsciiString(stfString)); + result.putInt(0); + result.putFloat(scale); + result.put(color.getBytes()); + result.putInt(displayType); + return result.flip(); + } else { + IoBuffer result = IoBuffer.allocate(124 + stfFile.length() + stfString.length()).order(ByteOrder.LITTLE_ENDIAN); + result.setAutoExpand(true); + result.putInt(ObjControllerMessage.SHOW_FLY_TEXT); + result.putLong(recieverId); + result.putInt(0); + result.putLong(objectId); + result.putLong(0); + result.putInt(unknownInt1); + result.putShort(unknownShort1); + result.put(unknownByte1); + result.putInt(unknownInt2); + result.put(getAsciiString(stfFile)); + result.putInt(0); + result.put(getAsciiString(stfString)); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putLong(0); + result.putInt(0); + result.putShort((short) unknownShort2); + result.putLong(0); + result.putFloat(scale); + result.put(color.getBytes()); + result.putInt(displayType); + return result.flip(); + } } } diff --git a/src/protocol/swg/objectControllerObjects/StartTask.java b/src/protocol/swg/objectControllerObjects/StartTask.java index f59ed3d7..c9946e73 100644 --- a/src/protocol/swg/objectControllerObjects/StartTask.java +++ b/src/protocol/swg/objectControllerObjects/StartTask.java @@ -25,8 +25,6 @@ import java.nio.ByteOrder; import org.apache.mina.core.buffer.IoBuffer; -import engine.resources.common.CRC; - import protocol.swg.ObjControllerMessage; public class StartTask extends ObjControllerObject { diff --git a/src/resources/common/Opcodes.java b/src/resources/common/Opcodes.java index 9bdfbc48..405cd992 100644 --- a/src/resources/common/Opcodes.java +++ b/src/resources/common/Opcodes.java @@ -29,6 +29,7 @@ public class Opcodes { public static int ChatInstantMessageToCharacter = 0x84BB21F7; public static int ChatPersistentMessageToServer = 0x25A29FA6; public static int ChatRequestPersistentMessage = 0x07E3559F; + public static int ChatSystemMessage = CRC.StringtoCRC("ChatSystemMessage"); public static int ClientOpenContainerMessage = 0x2D2D6EE1; public static int CmdSceneReady = 0x43FD1C22; public static int ConnectPlayerMessage = 0x2E365218; @@ -51,6 +52,8 @@ public class Opcodes { public static int GcwRegionsRsp = CRC.StringtoCRC("GcwRegionsRsp"); public static int GcwGroupsRsp = CRC.StringtoCRC("GcwGroupsRsp"); public static int ExpertiseRequestMessage = 0xC19085D5; + public static int ClientMfdStatusUpdateMessage = CRC.StringtoCRC("ClientMdfStatusUpdateMessage"); + public static int PlayMusicMessage = CRC.StringtoCRC("PlayMusicMessage"); public static int PlanetTravelPointListRequest = 0x96405D4D; } diff --git a/src/resources/common/RGB.java b/src/resources/common/RGB.java new file mode 100644 index 00000000..d5d62dde --- /dev/null +++ b/src/resources/common/RGB.java @@ -0,0 +1,37 @@ +package resources.common; + +import resources.objects.ListObject; + +public class RGB extends ListObject { + + private byte red, green, blue; + + public RGB(byte red, byte green, byte blue) { + this.red = red; + this.green = green; + this.blue = blue; + } + + public RGB(int red, int green, int blue) { + this.red = (byte) red; + this.green = (byte) green; + this.blue = (byte) blue; + } + + public byte getRed() { + return red; + } + + public byte getGreen() { + return green; + } + + public byte getBlue() { + return blue; + } + + public byte[] getBytes() { + return new byte[] { red, green, blue }; + } + +} diff --git a/src/resources/common/SpawnPoint.java b/src/resources/common/SpawnPoint.java index 0053d5d3..2068dbb4 100644 --- a/src/resources/common/SpawnPoint.java +++ b/src/resources/common/SpawnPoint.java @@ -40,6 +40,11 @@ public class SpawnPoint { this.setOrientation(orientation); } + public SpawnPoint(Point3D position, float oY, float oW) { + this.setPosition(position); + this.setOrientation(new Quaternion(oW, 0, oY, 0)); + } + public SpawnPoint(float x, float y, float z, float oY, float oW) { this.setPosition(new Point3D(x, y, z)); this.setOrientation(new Quaternion(oW, 0, oY, 0)); diff --git a/src/resources/common/StateStatus.java b/src/resources/common/StateStatus.java new file mode 100644 index 00000000..e4039a46 --- /dev/null +++ b/src/resources/common/StateStatus.java @@ -0,0 +1,47 @@ +package resources.common; + +public class StateStatus { + // States.iff + public static int Invalid = -1; + public static int Cover = 0; + public static int Combat = 1; + public static int Peace = 2; + public static int Aiming = 3; + public static int Alert = 4; + public static int Berserk = 5; + public static int FeignDeath = 6; + public static int CombatAttitudeEvasive = 7; + public static int CombatAttitudeNormal = 8; + public static int CombatAttitudeAggressive = 9; + public static int Tumbling = 10; + public static int Rallied = 11; + public static int Stunned = 12; + public static int Blinded = 13; + public static int Dizzy = 14; + public static int Intimidated =15; + public static int Immobilized = 16; + public static int Frozen = 17; + public static int Swimming = 18; + public static int SittingOnChair = 19; + public static int Crafting = 20; + public static int GlowingJedi = 21; + public static int MaskScent = 22; + public static int Poisoned = 23; + public static int Bleeding = 24; + public static int Diseased = 25; + public static int OnFire = 26; + public static int RidingMount = 27; + public static int MountedCreature = 28; + public static int PilotingShip = 29; + public static int ShipOperations = 30; + public static int ShipGunner = 31; + public static int ShipInterior = 32; + public static int PilotingPobShip = 33; + public static int PerformingDeathBlow = 34; + public static int Disguised = 35; + public static int ElectricBurned = 36; + public static int ColdBurned = 37; + public static int AcidBurned = 38; + public static int EnergyBurned = 39; + public static int KineticBurned = 40; +} diff --git a/src/resources/common/ThreadMonitor.java b/src/resources/common/ThreadMonitor.java new file mode 100644 index 00000000..43adcb64 --- /dev/null +++ b/src/resources/common/ThreadMonitor.java @@ -0,0 +1,226 @@ +/******************************************************************************* + * Copyright (c) 2013 + * + * This File is part of NGECore2. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Using NGEngine to work with NGECore2 is making a combined work based on NGEngine. + * Therefore all terms and conditions of the GNU Lesser General Public License cover the combination. + ******************************************************************************/ +package resources.common; + +import static java.lang.management.ManagementFactory.THREAD_MXBEAN_NAME; +import static java.lang.management.ManagementFactory.getThreadMXBean; +import static java.lang.management.ManagementFactory.newPlatformMXBeanProxy; + +import java.io.IOException; +import java.lang.management.LockInfo; +import java.lang.management.MonitorInfo; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.ReflectionException; + +public class ThreadMonitor { + + private MBeanServerConnection server; + + private ThreadMXBean tmbean; + + private ObjectName objname; + + // default - JDK 6+ VM + private String findDeadlocksMethodName = "findDeadlockedThreads"; + + private boolean canDumpLocks = true; + + /** + * Constructs a ThreadMonitor object to get thread information in the local + * JVM. + */ + public ThreadMonitor() { + this.tmbean = getThreadMXBean(); + } + + /** + * Prints the thread dump information to System.out. + */ + public void threadDump() { + if (canDumpLocks) { + if (tmbean.isObjectMonitorUsageSupported() && tmbean.isSynchronizerUsageSupported()) { + dumpThreadInfoWithLocks(); + } + } else { + dumpThreadInfo(); + } + } + + private void dumpThreadInfo() { + System.out.println("Full Java thread dump"); + long[] tids = tmbean.getAllThreadIds(); + ThreadInfo[] tinfos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE); + for (ThreadInfo ti : tinfos) { + printThreadInfo(ti); + } + } + + /** + * Prints the thread dump information with locks info to System.out. + */ + private void dumpThreadInfoWithLocks() { + System.out.println("Full Java thread dump with locks info"); + + ThreadInfo[] tinfos = tmbean.dumpAllThreads(true, true); + for (ThreadInfo ti : tinfos) { + printThreadInfo(ti); + LockInfo[] syncs = ti.getLockedSynchronizers(); + printLockInfo(syncs); + } + System.out.println(); + } + + private static String INDENT = " "; + + private void printThreadInfo(ThreadInfo ti) { + // print thread information + printThread(ti); + + // print stack trace with locks + StackTraceElement[] stacktrace = ti.getStackTrace(); + MonitorInfo[] monitors = ti.getLockedMonitors(); + for (int i = 0; i < stacktrace.length; i++) { + StackTraceElement ste = stacktrace[i]; + System.out.println(INDENT + "at " + ste.toString()); + for (MonitorInfo mi : monitors) { + if (mi.getLockedStackDepth() == i) { + System.out.println(INDENT + " - locked " + mi); + } + } + } + System.out.println(); + } + + private void printThread(ThreadInfo ti) { + StringBuilder sb = new StringBuilder("\"" + ti.getThreadName() + "\"" + " Id=" + + ti.getThreadId() + " in " + ti.getThreadState()); + if (ti.getLockName() != null) { + sb.append(" on lock=" + ti.getLockName()); + } + if (ti.isSuspended()) { + sb.append(" (suspended)"); + } + if (ti.isInNative()) { + sb.append(" (running in native)"); + } + System.out.println(sb.toString()); + if (ti.getLockOwnerName() != null) { + System.out.println(INDENT + " owned by " + ti.getLockOwnerName() + " Id=" + + ti.getLockOwnerId()); + } + } + + private void printMonitorInfo(ThreadInfo ti, MonitorInfo[] monitors) { + System.out.println(INDENT + "Locked monitors: count = " + monitors.length); + for (MonitorInfo mi : monitors) { + System.out.println(INDENT + " - " + mi + " locked at "); + System.out.println(INDENT + " " + mi.getLockedStackDepth() + " " + + mi.getLockedStackFrame()); + } + } + + private void printLockInfo(LockInfo[] locks) { + System.out.println(INDENT + "Locked synchronizers: count = " + locks.length); + for (LockInfo li : locks) { + System.out.println(INDENT + " - " + li); + } + System.out.println(); + } + + /** + * Checks if any threads are deadlocked. If any, print the thread dump + * information. + */ + public boolean findDeadlock() { + long[] tids; + if (findDeadlocksMethodName.equals("findDeadlockedThreads") + && tmbean.isSynchronizerUsageSupported()) { + tids = tmbean.findDeadlockedThreads(); + if (tids == null) { + return false; + } + + System.out.println("Deadlock found :-"); + ThreadInfo[] infos = tmbean.getThreadInfo(tids, true, true); + for (ThreadInfo ti : infos) { + printThreadInfo(ti); + printLockInfo(ti.getLockedSynchronizers()); + System.out.println(); + } + } else { + tids = tmbean.findMonitorDeadlockedThreads(); + if (tids == null) { + return false; + } + ThreadInfo[] infos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE); + for (ThreadInfo ti : infos) { + // print thread information + printThreadInfo(ti); + } + } + + return true; + } + + private void parseMBeanInfo() throws IOException { + try { + MBeanOperationInfo[] mopis = server.getMBeanInfo(objname).getOperations(); + + // look for findDeadlockedThreads operations; + boolean found = false; + for (MBeanOperationInfo op : mopis) { + if (op.getName().equals(findDeadlocksMethodName)) { + found = true; + break; + } + } + if (!found) { + findDeadlocksMethodName = "findMonitorDeadlockedThreads"; + canDumpLocks = false; + } + } catch (IntrospectionException e) { + InternalError ie = new InternalError(e.getMessage()); + ie.initCause(e); + throw ie; + } catch (InstanceNotFoundException e) { + InternalError ie = new InternalError(e.getMessage()); + ie.initCause(e); + throw ie; + } catch (ReflectionException e) { + InternalError ie = new InternalError(e.getMessage()); + ie.initCause(e); + throw ie; + } + } + } \ No newline at end of file diff --git a/src/resources/objects/creature/CreatureMessageBuilder.java b/src/resources/objects/creature/CreatureMessageBuilder.java index aba6bf2c..4c92f9f2 100644 --- a/src/resources/objects/creature/CreatureMessageBuilder.java +++ b/src/resources/objects/creature/CreatureMessageBuilder.java @@ -57,7 +57,13 @@ public class CreatureMessageBuilder extends ObjectMessageBuilder { buffer.putInt(creature.getBankCredits()); buffer.putInt(creature.getCashCredits()); - buffer.putInt(0); // Base HAM List most likely unused in NGE + buffer.putInt(6); // Base HAM List - so leveling knows the base HAM, before equipment etc + buffer.putInt(6); + buffer.putInt(creature.getHealth()); + buffer.putInt(0); + buffer.putInt(creature.getAction()); + buffer.putInt(0); + buffer.putInt(0x2C01); buffer.putInt(0); if(creature.getSkills().isEmpty()) { @@ -89,6 +95,7 @@ public class CreatureMessageBuilder extends ObjectMessageBuilder { buffer.put(getAsciiString(creature.getStfFilename())); buffer.putInt(0); buffer.put(getAsciiString(creature.getStfName())); + if (creature.getCustomName() == null) { creature.setCustomName(""); }//Not all CreatureObjects have CustomName (Shuttles) buffer.put(getUnicodeString(creature.getCustomName())); buffer.putInt(0x000F4240); // unk String factionCRC = creature.getFaction(); @@ -103,7 +110,7 @@ public class CreatureMessageBuilder extends ObjectMessageBuilder { byte[] customizationData = creature.getCustomization(); - if(customizationData.length <= 0) + if(customizationData == null || customizationData.length <= 0) // Shuttles have no customization data buffer.putShort((short) 0); else { buffer.putShort((short) customizationData.length); @@ -225,7 +232,7 @@ public class CreatureMessageBuilder extends ObjectMessageBuilder { buffer.putShort(creature.getLevel()); //buffer.putShort((short) 90); - buffer.putInt(0xD007); // unk + buffer.putInt(creature.getGrantedHealth()); // From player_level.iff. Ranges from 0-2000 as you level, consistent with that table. if(creature.getCurrentAnimation() == null || creature.getCurrentAnimation().length() == 0) buffer.putShort((short) 0); @@ -570,6 +577,15 @@ public class CreatureMessageBuilder extends ObjectMessageBuilder { } + public IoBuffer buildGrantedHealthDelta(int grantedHealth) { + IoBuffer buffer = bufferPool.allocate(4, false).order(ByteOrder.LITTLE_ENDIAN); + buffer.putInt(grantedHealth); + int size = buffer.position(); + buffer.flip(); + buffer = createDelta("CREO", (byte) 6, (short) 1, (short) 9, buffer, size + 4); + return buffer; + } + public IoBuffer buildLevelDelta(short level) { IoBuffer buffer = bufferPool.allocate(2, false).order(ByteOrder.LITTLE_ENDIAN); diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index 48663806..0d953575 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -30,14 +30,11 @@ import org.apache.mina.core.buffer.IoBuffer; import protocol.swg.ChatSystemMessage; import protocol.swg.ObjControllerMessage; -import protocol.swg.PlayClientEffectObjectMessage; -import protocol.swg.StopClientEffectObjectByLabel; +import protocol.swg.PlayMusicMessage; import protocol.swg.UpdatePVPStatusMessage; import protocol.swg.UpdatePostureMessage; import protocol.swg.objectControllerObjects.Posture; - - import com.sleepycat.je.Environment; import com.sleepycat.je.Transaction; import com.sleepycat.persist.model.Entity; @@ -104,7 +101,8 @@ public class CreatureObject extends TangibleObject implements IPersistent { // CREO6 private byte combatFlag = 0; - private short level = 90; + private short level = 1; + private int grantedHealth = 0; private String currentAnimation; private String moodAnimation; private long weaponId = 0; @@ -117,12 +115,12 @@ public class CreatureObject extends TangibleObject implements IPersistent { private byte moodId = 0; private int performanceCounter = 0; private int performanceId = 0; - private int health = 20000; - private int action = 12500; + private int health = 1000; + private int action = 300; @NotPersistent private int HAMListCounter = 0; - private int maxHealth = 20000; - private int maxAction = 12500; + private int maxHealth = 1000; + private int maxAction = 300; @NotPersistent private int maxHAMListCounter = 0; @@ -202,6 +200,18 @@ public class CreatureObject extends TangibleObject implements IPersistent { return skills; } + public boolean hasSkill(String name) { + synchronized(objectMutex) { + for (String skill : skills) { + if (skill.equals(name)) { + return true; + } + } + + return false; + } + } + public short getSkillsUpdateCounter() { synchronized(objectMutex) { return (short) skillsUpdateCounter; @@ -394,11 +404,16 @@ public class CreatureObject extends TangibleObject implements IPersistent { return skillMod; } } + return null; } + public int getSkillModBase(String name) { + SkillMod skillMod = getSkillMod(name); + return ((skillMod == null) ? 0 : skillMod.getBase()); + } + public void addSkillMod(String name, int base) { - if(getSkillMod(name) == null) { SkillMod skillMod = new SkillMod(); skillMod.setBase(base); @@ -579,6 +594,16 @@ public class CreatureObject extends TangibleObject implements IPersistent { public SWGList getAbilities() { return abilities; } + + public boolean hasAbility(String name) { + for (String ability : abilities) { + if (ability.equals(name)) { + return true; + } + } + + return false; + } public int getAbilitiesUpdateCounter() { synchronized(objectMutex) { @@ -657,6 +682,20 @@ public class CreatureObject extends TangibleObject implements IPersistent { notifyObservers(levelDelta, true); } + + public int getGrantedHealth() { + synchronized(objectMutex) { + return grantedHealth; + } + } + + public void setGrantedHealth(int grantedHealth) { + synchronized(objectMutex) { + this.grantedHealth = grantedHealth; + } + + notifyObservers(messageBuilder.buildGrantedHealthDelta(grantedHealth), true); + } public String getCurrentAnimation() { synchronized(objectMutex) { @@ -912,6 +951,15 @@ public class CreatureObject extends TangibleObject implements IPersistent { } } + + public void sendSystemMessage(String stfFilename, String stfName, int stat, int displayType) { + + if(getClient() != null && getClient().getSession() != null) { + ChatSystemMessage systemMsg = new ChatSystemMessage(stfFilename, stfName, stat, (byte) displayType); + getClient().getSession().write(systemMsg.serialize()); + } + + } public int getHealth() { synchronized(objectMutex) { @@ -1099,14 +1147,6 @@ public class CreatureObject extends TangibleObject implements IPersistent { } } - public void playEffectObject(String effectFile, String commandString) { - notifyObservers(new PlayClientEffectObjectMessage(effectFile, getObjectID(), commandString), true); - } - - public void stopEffectObject(String commandString) { - notifyObservers(new StopClientEffectObjectByLabel(getObjectID(), commandString), true); - } - public SWGList getDotList() { return dotList; } @@ -1162,4 +1202,25 @@ public class CreatureObject extends TangibleObject implements IPersistent { if(incapTask != null) incapTask.cancel(true); } + + public void playMusic(String sndFile) { + playMusic(sndFile, 0, 1, false); + } + + public void playMusic(String sndFile, long targetId) { + playMusic(sndFile, targetId, 1, false); + } + + public void playMusic(String sndFile, int repetitions) { + playMusic(sndFile, 0, repetitions, false); + } + + public void playMusic(String sndFile, long targetId, int repetitions) { + playMusic(sndFile, targetId, repetitions, false); + } + + public void playMusic(String sndFile, long targetId, int repetitions, boolean flag) { + getClient().getSession().write(new PlayMusicMessage(sndFile, targetId, 1, false)); + } + } diff --git a/src/resources/objects/group/GroupObject.java b/src/resources/objects/group/GroupObject.java index 168897bd..e87a0950 100644 --- a/src/resources/objects/group/GroupObject.java +++ b/src/resources/objects/group/GroupObject.java @@ -23,9 +23,6 @@ package resources.objects.group; import java.util.Vector; -import org.apache.mina.core.buffer.IoBuffer; - -import resources.objects.SWGList; import engine.clients.Client; import engine.resources.objects.SWGObject; import engine.resources.scene.Point3D; diff --git a/src/resources/objects/player/PlayerMessageBuilder.java b/src/resources/objects/player/PlayerMessageBuilder.java index d3775ea2..cb480a88 100644 --- a/src/resources/objects/player/PlayerMessageBuilder.java +++ b/src/resources/objects/player/PlayerMessageBuilder.java @@ -26,6 +26,8 @@ import java.util.Map.Entry; import org.apache.mina.core.buffer.IoBuffer; +import engine.resources.common.CRC; + import resources.objects.ObjectMessageBuilder; import resources.objects.waypoint.WaypointObject; @@ -375,6 +377,30 @@ public class PlayerMessageBuilder extends ObjectMessageBuilder { } + public IoBuffer buildXPListDelta(String type, int amount, boolean alreadyExists) { + PlayerObject player = (PlayerObject) object; + player.setXpListUpdateCounter(player.getXpListUpdateCounter() + 1); + + // Some problem with createDelta() + IoBuffer result = bufferPool.allocate(42 + type.length(), false).order(ByteOrder.LITTLE_ENDIAN); + result.putShort((short) 5); + result.putInt(CRC.StringtoCRC("BaselinesMessage")); + result.putLong(object.getContainer().getObjectID()); + result.put("YALP".getBytes()); + result.put((byte) 8); + result.putInt(19 + type.length()); + result.putShort((short) 1); + result.putShort((short) 0); + result.putInt(1); + result.putInt(player.getXpListUpdateCounter()); + result.put((byte) ((alreadyExists) ? 2 : 0)); + result.putShort((short) type.length()); + result.put(type.getBytes()); + result.putInt(amount); + + return result.flip(); + } + public IoBuffer buildWaypointAddDelta(WaypointObject waypoint) { PlayerObject player = (PlayerObject) object; diff --git a/src/resources/objects/player/PlayerObject.java b/src/resources/objects/player/PlayerObject.java index 75ee468e..4995dfb0 100644 --- a/src/resources/objects/player/PlayerObject.java +++ b/src/resources/objects/player/PlayerObject.java @@ -201,7 +201,39 @@ public class PlayerObject extends SWGObject { public Map getXpList() { return xpList; } - + + public int getXp(String type) { + synchronized(objectMutex) { + return ((!xpList.containsKey(type)) ? 0 : xpList.get(type)); + } + } + + // Temporary + public void setXp(String type, int amount) { + boolean xpExists; + + synchronized(objectMutex) { + xpExists = xpList.containsKey(type); + xpList.put(type, amount); + } + + if (getContainer() != null && getContainer().getClient() != null && getContainer().getClient().getSession() != null) { + getContainer().getClient().getSession().write(messageBuilder.buildXPListDelta(type, amount, xpExists)); + } + } + + public int getXpListUpdateCounter() { + synchronized(objectMutex) { + return xpListUpdateCounter; + } + } + + public void setXpListUpdateCounter(int xpListUpdateCounter) { + synchronized(objectMutex) { + this.xpListUpdateCounter = xpListUpdateCounter; + } + } + public List getWaypoints() { return waypoints; } diff --git a/src/resources/objects/staticobject/StaticMessageBuilder.java b/src/resources/objects/staticobject/StaticMessageBuilder.java index be3afa20..696954f3 100644 --- a/src/resources/objects/staticobject/StaticMessageBuilder.java +++ b/src/resources/objects/staticobject/StaticMessageBuilder.java @@ -26,7 +26,6 @@ import java.nio.ByteOrder; import org.apache.mina.core.buffer.IoBuffer; import resources.objects.ObjectMessageBuilder; -import resources.objects.tangible.TangibleObject; public class StaticMessageBuilder extends ObjectMessageBuilder { diff --git a/src/resources/objects/tangible/TangibleObject.java b/src/resources/objects/tangible/TangibleObject.java index 157ef125..1c6eb9f7 100644 --- a/src/resources/objects/tangible/TangibleObject.java +++ b/src/resources/objects/tangible/TangibleObject.java @@ -23,8 +23,15 @@ package resources.objects.tangible; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.Vector; +import protocol.swg.ObjControllerMessage; +import protocol.swg.PlayClientEffectObjectMessage; +import protocol.swg.StopClientEffectObjectByLabel; +import protocol.swg.objectControllerObjects.ShowFlyText; + +import resources.common.RGB; import resources.objects.creature.CreatureObject; @@ -221,8 +228,39 @@ public class TangibleObject extends SWGObject { return getPvPBitmask() == 1 || getPvPBitmask() == 2; } - - + + public void showFlyText(String stfFile, String stfString, float scale, RGB color, int displayType) { + Set observers = getObservers(); + + if (getClient() != null) { + getClient().getSession().write((new ObjControllerMessage(0x0000000B, new ShowFlyText(getObjectID(), getObjectID(), stfFile, stfString, scale, color, displayType))).serialize()); + } + + for (Client client : observers) { + client.getSession().write((new ObjControllerMessage(0x0000000B, new ShowFlyText(client.getParent().getObjectID(), getObjectID(), stfFile, stfString, scale, color, displayType))).serialize()); + } + } + + public void showFlyText(String stfFile, String stfString, int xp, float scale, RGB color, int displayType) { + Set observers = getObservers(); + + if (getClient() != null) { + getClient().getSession().write((new ObjControllerMessage(0x0000000B, new ShowFlyText(getObjectID(), getObjectID(), 56, 1, 1, -1, stfFile, stfString, xp, scale, color, displayType))).serialize()); + } + + for (Client client : observers) { + client.getSession().write((new ObjControllerMessage(0x0000000B, new ShowFlyText(client.getParent().getObjectID(), getObjectID(), 56, 1, 1, -1, stfFile, stfString, xp, scale, color, displayType))).serialize()); + } + } + + public void playEffectObject(String effectFile, String commandString) { + notifyObservers(new PlayClientEffectObjectMessage(effectFile, getObjectID(), commandString), true); + } + + public void stopEffectObject(String commandString) { + notifyObservers(new StopClientEffectObjectByLabel(getObjectID(), commandString), true); + } + @Override public void sendBaselines(Client destination) { diff --git a/src/services/BuffService.java b/src/services/BuffService.java index 87e5d77b..8ba2894f 100644 --- a/src/services/BuffService.java +++ b/src/services/BuffService.java @@ -36,7 +36,6 @@ import resources.objects.player.PlayerObject; import main.NGECore; -import engine.resources.common.CRC; import engine.resources.service.INetworkDispatch; import engine.resources.service.INetworkRemoteEvent; diff --git a/src/services/CharacterService.java b/src/services/CharacterService.java index 362446ba..050b6ab7 100644 --- a/src/services/CharacterService.java +++ b/src/services/CharacterService.java @@ -45,6 +45,7 @@ import engine.resources.service.INetworkRemoteEvent; import resources.common.*; import protocol.swg.ClientCreateCharacter; +import protocol.swg.ClientMfdStatusUpdateMessage; import protocol.swg.ClientRandomNameRequest; import protocol.swg.ClientRandomNameResponse; import protocol.swg.ClientVerifyAndLockNameRequest; @@ -207,17 +208,29 @@ public class CharacterService implements INetworkDispatch { // should set to some planet and starting location String sharedRaceTemplate = raceTemplate.replace("player/", "player/shared_"); - CreatureObject object = (CreatureObject) core.objectService.createObject(sharedRaceTemplate, core.terrainService.getPlanetByName("naboo")); + CreatureObject object = (CreatureObject) core.objectService.createObject(sharedRaceTemplate, core.terrainService.getPlanetByName("tatooine")); object.setContainerPermissions(CreaturePermissions.CREATURE_PERMISSIONS); object.setCustomization(clientCreateCharacter.getCustomizationData()); object.setCustomName(clientCreateCharacter.getName()); object.setHeight(clientCreateCharacter.getScale()); object.setPersistent(true); - object.setPosition(new Point3D(-5567, 0, -32)); + object.setPosition(new Point3D(3528, 0, -4804)); object.setCashCredits(100); object.setBankCredits(1000); //object.setPosition(new Point3D(0, 0, 0)); object.setOrientation(new Quaternion(1, 0, 0, 0)); + float luck = (((((float) (core.scriptService.getMethod("scripts/roadmap/", clientCreateCharacter.getProfession(), "getLuck").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", object.getStfName(), "getLuck").__call__().asInt())) / ((float) 90)) * ((float) object.getLevel())) - ((float) object.getSkillModBase("luck"))); + float precision = (((((float) (core.scriptService.getMethod("scripts/roadmap/", clientCreateCharacter.getProfession(), "getPrecision").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", object.getStfName(), "getPrecision").__call__().asInt())) / ((float) 90)) * ((float) object.getLevel())) - ((float) object.getSkillModBase("precision"))); + float strength = (((((float) (core.scriptService.getMethod("scripts/roadmap/", clientCreateCharacter.getProfession(), "getStrength").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", object.getStfName(), "getStrength").__call__().asInt())) / ((float) 90)) * ((float) object.getLevel())) - ((float) object.getSkillModBase("strength"))); + float constitution = (((((float) (core.scriptService.getMethod("scripts/roadmap/", clientCreateCharacter.getProfession(), "getConstitution").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", object.getStfName(), "getConstitution").__call__().asInt())) / ((float) 90)) * ((float) object.getLevel())) - ((float) object.getSkillModBase("constitution"))); + float stamina = (((((float) (core.scriptService.getMethod("scripts/roadmap/", clientCreateCharacter.getProfession(), "getStamina").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", object.getStfName(), "getStamina").__call__().asInt())) / ((float) 90)) * ((float) object.getLevel())) - ((float) object.getSkillModBase("stamina"))); + float agility = (((((float) (core.scriptService.getMethod("scripts/roadmap/", clientCreateCharacter.getProfession(), "getAgility").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", object.getStfName(), "getAgility").__call__().asInt())) / ((float) 90)) * ((float) object.getLevel())) - ((float) object.getSkillModBase("agility"))); + if (luck >= 1) core.skillModService.addSkillMod(object, "luck", (int) luck); + if (precision >= 1) core.skillModService.addSkillMod(object, "precision", (int) precision); + if (strength >= 1) core.skillModService.addSkillMod(object, "strength", (int) strength); + if (constitution >= 1) core.skillModService.addSkillMod(object, "constitution", (int) constitution); + if (stamina >= 1) core.skillModService.addSkillMod(object, "stamina", (int) stamina); + if (agility >= 1) core.skillModService.addSkillMod(object, "agility", (int) agility); object.createTransaction(core.getCreatureODB().getEnvironment()); PlayerObject player = (PlayerObject) core.objectService.createObject("object/player/shared_player.iff", object.getPlanet()); @@ -266,7 +279,7 @@ public class CharacterService implements INetworkDispatch { core.scriptService.callScript("scripts/", "starterclothing", "CreateStarterClothing", core, object, clientCreateCharacter.getStarterProfession(), clientCreateCharacter.getRaceTemplate()); core.scriptService.callScript("scripts/", "CreateStartingCharacter", "demo", core, object); - + core.getCreatureODB().put(object, Long.class, CreatureObject.class, object.getTransaction()); // might not need to commit transaction but better safe than sorry object.getTransaction().commitSync(); @@ -288,7 +301,7 @@ public class CharacterService implements INetworkDispatch { session.write(core.loginService.getLoginClusterStatus().serialize()); session.write(success.serialize()); - + session.write((new ClientMfdStatusUpdateMessage((float) 2, "/GroundHUD.MFDStatus.vsp.role.targetLevel")).serialize()); } }); diff --git a/src/services/EquipmentService.java b/src/services/EquipmentService.java new file mode 100644 index 00000000..8223e3b0 --- /dev/null +++ b/src/services/EquipmentService.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2013 + * + * This File is part of NGECore2. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Using NGEngine to work with NGECore2 is making a combined work based on NGEngine. + * Therefore all terms and conditions of the GNU Lesser General Public License cover the combination. + ******************************************************************************/ +package services; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; +import org.python.core.Py; +import org.python.core.PyObject; +import resources.objects.creature.CreatureObject; +import main.NGECore; +import engine.resources.objects.SWGObject; +import engine.resources.service.INetworkDispatch; +import engine.resources.service.INetworkRemoteEvent; + +public class EquipmentService implements INetworkDispatch { + + private NGECore core; + + public EquipmentService(NGECore core) { + this.core = core; + } + + @Override + public void insertOpcodes(Map arg0, Map arg1) { + + } + + @Override + public void shutdown() { + + } + + public void equip(CreatureObject actor, SWGObject item, SWGObject replacedItem) { + + if(replacedItem != null) + unequip(actor, replacedItem); + + String template = item.getTemplate(); + String serverTemplate = template.replace(".iff", ""); + PyObject func = core.scriptService.getMethod("scripts/" + serverTemplate.split("shared_" , 2)[0].replace("shared_", ""), serverTemplate.split("shared_" , 2)[1], "equip"); + if(func != null) + func.__call__(Py.java2py(core), Py.java2py(actor), Py.java2py(item)); + + // TODO: add health/action bonus from crafted weapon with augmentations + + Map attributes = new TreeMap(item.getAttributes()); + + for(Entry e : attributes.entrySet()) { + + if(e.getKey().startsWith("cat_skill_mod_bonus.@stat_n:")) { + core.skillModService.addSkillMod(actor, e.getKey().replace("cat_skill_mod_bonus.@stat_n:", ""), Integer.parseInt((String) e.getValue())); + } + + } + + } + + public void unequip(CreatureObject actor, SWGObject item) { + + String template = item.getTemplate(); + String serverTemplate = template.replace(".iff", ""); + PyObject func = core.scriptService.getMethod("scripts/" + serverTemplate.split("shared_" , 2)[0].replace("shared_", ""), serverTemplate.split("shared_" , 2)[1], "unequip"); + if(func != null) + func.__call__(Py.java2py(core), Py.java2py(actor), Py.java2py(item)); + + // TODO: remove health/action bonus from crafted weapon with augmentations + + Map attributes = new TreeMap(item.getAttributes()); + + for(Entry e : attributes.entrySet()) { + + if(e.getKey().startsWith("cat_skill_mod_bonus.@stat_n:")) { + core.skillModService.deductSkillMod(actor, e.getKey().replace("cat_skill_mod_bonus.@stat_n:", ""), Integer.parseInt((String) e.getValue())); + } + + } + + } + + +} diff --git a/src/services/PlayerService.java b/src/services/PlayerService.java index 6f2d3beb..8e97f5de 100644 --- a/src/services/PlayerService.java +++ b/src/services/PlayerService.java @@ -36,10 +36,13 @@ import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.IoSession; import protocol.swg.ClientIdMsg; +import protocol.swg.ClientMfdStatusUpdateMessage; import protocol.swg.ExpertiseRequestMessage; import protocol.swg.ServerTimeMessage; +import protocol.swg.objectControllerObjects.ShowFlyText; import resources.common.FileUtilities; import resources.common.Opcodes; +import resources.common.RGB; import resources.common.SpawnPoint; import resources.objects.Buff; import resources.objects.building.BuildingObject; @@ -53,7 +56,12 @@ import services.sui.SUIWindow.SUICallback; import main.NGECore; +import engine.clientdata.ClientFileManager; +import engine.clientdata.visitors.CrcStringTableVisitor; +import engine.clientdata.visitors.DatatableVisitor; import engine.clients.Client; +import engine.resources.common.CRC; +import engine.resources.objects.DraftSchematic; import engine.resources.objects.SWGObject; import engine.resources.scene.Point3D; import engine.resources.service.INetworkDispatch; @@ -65,7 +73,9 @@ public class PlayerService implements INetworkDispatch { private NGECore core; private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - + + protected final Object objectMutex = new Object(); + public PlayerService(final NGECore core) { this.core = core; scheduler.scheduleAtFixedRate(new Runnable() { @@ -293,7 +303,189 @@ public class PlayerService implements INetworkDispatch { core.buffService.addBuffToCreature(creature, "cloning_sickness"); } - + + /* + * Gives experience. If they have enough experience, it auto-levels them up. + * + * First, it adds the experience. + * Second, it sees if they need to level up. + * Third, if they do, it adds the relevant stat/health/action increases & expertise points. + * Fourth, if their roadmap increased, it adds the relevant roadmap update, roadmap items, skillmods, abilities, and profession quests. + * ALL of this info is contained in the client files, so we don't need to bother with scripts. + */ + public void giveExperience(CreatureObject creature, int experience) { + DatatableVisitor experienceTable; + PlayerObject player = (PlayerObject) creature.getSlottedObject("ghost"); + + synchronized(objectMutex) { + try { + experienceTable = ClientFileManager.loadFile("datatables/player/player_level.iff", DatatableVisitor.class); + + // Cannot gain more than half of the XP needed for the next level in one go + // Do check + + // 1. Add the experience. + if (experience > 0) { + creature.showFlyText("base_player", "prose_flytext_xp", experience, (float) 2.5, new RGB(180, 60, 240), 1); + } + + String xpType = ((player.getProfession().contains("entertainer")) ? "entertainer" : ((player.getProfession().contains("trader")) ? "crafting" : "combat_general")); + + if (player.getXpList().containsKey(xpType)) { + experience += player.getXp(xpType); + } + + player.setXp(xpType, experience); + + // 2. See if they need to level up. + for (int i = 0; i < experienceTable.getRowCount(); i++) { + if (experienceTable.getObject(i, 0) != null) { + if (experience >= ((Integer) experienceTable.getObject(i, 1))) { + if (creature.getLevel() < (Integer) experienceTable.getObject(i, 0)) { + creature.playEffectObject("clienteffect/level_granted.cef", ""); + creature.getClient().getSession().write((new ClientMfdStatusUpdateMessage((float) ((creature.getLevel() == 90) ? 90 : (creature.getLevel() + 1)), "/GroundHUD.MFDStatus.vsp.role.targetLevel")).serialize()); + creature.setLevel(((Integer) experienceTable.getObject(i, 0)).shortValue()); + + // 3. Add the relevant health/action and expertise points. + float luck = (((((float) (core.scriptService.getMethod("scripts/roadmap/", player.getProfession(), "getLuck").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", creature.getStfName(), "getLuck").__call__().asInt())) / ((float) 90)) * ((float) creature.getLevel())) - ((float) creature.getSkillModBase("luck"))); + float precision = (((((float) (core.scriptService.getMethod("scripts/roadmap/", player.getProfession(), "getPrecision").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", creature.getStfName(), "getPrecision").__call__().asInt())) / ((float) 90)) * ((float) creature.getLevel())) - ((float) creature.getSkillModBase("precision"))); + float strength = (((((float) (core.scriptService.getMethod("scripts/roadmap/", player.getProfession(), "getStrength").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", creature.getStfName(), "getStrength").__call__().asInt())) / ((float) 90)) * ((float) creature.getLevel())) - ((float) creature.getSkillModBase("strength"))); + float constitution = (((((float) (core.scriptService.getMethod("scripts/roadmap/", player.getProfession(), "getConstitution").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", creature.getStfName(), "getConstitution").__call__().asInt())) / ((float) 90)) * ((float) creature.getLevel())) - ((float) creature.getSkillModBase("constitution"))); + float stamina = (((((float) (core.scriptService.getMethod("scripts/roadmap/", player.getProfession(), "getStamina").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", creature.getStfName(), "getStamina").__call__().asInt())) / ((float) 90)) * ((float) creature.getLevel())) - ((float) creature.getSkillModBase("stamina"))); + float agility = (((((float) (core.scriptService.getMethod("scripts/roadmap/", player.getProfession(), "getAgility").__call__().asInt()) + (core.scriptService.getMethod("scripts/roadmap/", creature.getStfName(), "getAgility").__call__().asInt())) / ((float) 90)) * ((float) creature.getLevel())) - ((float) creature.getSkillModBase("agility"))); + float health = 100; + float action = 75; + + int healthGranted = ((Integer) experienceTable.getObject(i, 4)); + + if (luck >= 1) { + core.skillModService.addSkillMod(creature, "luck", (int) luck); + creature.sendSystemMessage("spam", "level_up_stat_gain_0", (int) luck, 0); + } + + if (precision >= 1) { + core.skillModService.addSkillMod(creature, "precision", (int) precision); + creature.sendSystemMessage("spam", "level_up_stat_gain_1", (int) precision, 0); + } + + if (strength >= 1) { + core.skillModService.addSkillMod(creature, "strength", (int) strength); + creature.sendSystemMessage("spam", "level_up_stat_gain_2", (int) strength, 0); + } + + if (constitution >= 1) { + core.skillModService.addSkillMod(creature, "constitution", (int) constitution); + creature.sendSystemMessage("spam", "level_up_stat_gain_3", (int) constitution, 0); + } + + if (stamina >= 1) { + core.skillModService.addSkillMod(creature, "stamina", (int) stamina); + creature.sendSystemMessage("spam", "level_up_stat_gain_4", (int) stamina, 0); + } + + if (agility >= 1) { + core.skillModService.addSkillMod(creature, "agility", (int) agility); + creature.sendSystemMessage("spam", "level_up_stat_gain_5", (int) agility, 0); + } + + if (health >= 1) { + creature.setMaxHealth((creature.getMaxHealth() + (int) health + (healthGranted - creature.getGrantedHealth()))); + creature.setHealth(creature.getMaxHealth()); + creature.sendSystemMessage("spam", "level_up_stat_gain_6", (((int) health) + (((int) constitution) * 8) + (((int) stamina) * 2)), 0); + } + + if (action >= 1) { + creature.setMaxAction((creature.getMaxAction() + (int) action)); + creature.setAction(creature.getMaxAction()); + creature.sendSystemMessage("spam", "level_up_stat_gain_7", (((int) action) + (((int) stamina) * 8) + (((int) constitution) * 2)), 0); + } + + creature.setGrantedHealth(((Integer) experienceTable.getObject(i, 4))); + // -> Expertise point added automatically by client + creature.showFlyText("cbt_spam", "level_up", (float) 2.5, new RGB(100, 149, 237), 0); + + // 4. Adds roadmap rewards + int level = creature.getLevel(); + + if ((level == 4 || level == 7 || level == 10) || ((level > 10) && (((creature.getLevel() - 10) % 4) == 0))) { + int skill = ((level <= 10) ? ((level - 1) / 3) : ((((level - 10) / 4)) + 3)); + String roadmapSkillName = ""; + DatatableVisitor skillTemplate, roadmap; + + try { + skillTemplate = ClientFileManager.loadFile("datatables/skill_template/skill_template.iff", DatatableVisitor.class); + + for (int s = 0; s < skillTemplate.getRowCount(); s++) { + if (skillTemplate.getObject(s, 0) != null) { + if (((String) skillTemplate.getObject(s, 0)).equals(player.getProfession())) { + String[] skillArray = ((String) skillTemplate.getObject(s, 4)).split(","); + roadmapSkillName = skillArray[skill]; + break; + } + } + } + + creature.showFlyText("cbt_spam", "skill_up", (float) 2.5, new RGB(154, 205, 50), 0); + creature.playEffectObject("clienteffect/skill_granted.cef", ""); + creature.playMusic("sound/music_acq_bountyhunter.snd"); + core.skillService.addSkill(creature, roadmapSkillName); + player.setProfessionWheelPosition(roadmapSkillName); + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + + try { + roadmap = ClientFileManager.loadFile("datatables/roadmap/item_rewards.iff", DatatableVisitor.class); + + for (int s = 0; s < roadmap.getRowCount(); s++) { + if (roadmap.getObject(s, 0) != null) { + if (((String) roadmap.getObject(s, 1)).equals(roadmapSkillName)) { + String[] apts = ((String) roadmap.getObject(s, 2)).split(","); + String[] items = ((String) roadmap.getObject(s, 4)).split(","); + String[] wookieeItems = ((String) roadmap.getObject(s, 5)).split(","); + String[] ithorianItems = ((String) roadmap.getObject(s, 6)).split(","); + + for (int n = 0; n < items.length; n++) { + String item = items[n]; + + if (wookieeItems.length > 0 && creature.getStfName().contains("wookiee")) { + item = wookieeItems[n]; + } else if (ithorianItems.length > 0 && creature.getStfName().contains("ithorian")) { + item = ithorianItems[n]; + } + + try { + if (!item.contains("/")) { + item = core.scriptService.callScript("scripts/roadmap/", "roadmap_rewards", "get", item).asString(); + } + + if (item != null && item != "") { + creature.getSlottedObject("inventory").add(core.objectService.createObject(item, creature.getPlanet())); + } else { + //System.out.println("Can't find template: " + item); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + } + } + } + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + } + } + } + } + } + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + } + } + @Override public void shutdown() { // TODO Auto-generated method stub diff --git a/src/services/ScriptService.java b/src/services/ScriptService.java index beac5ff5..e7d3b966 100644 --- a/src/services/ScriptService.java +++ b/src/services/ScriptService.java @@ -38,7 +38,7 @@ public class ScriptService { this.core = core; } - public void callScript(String path, String module, String method) { + public PyObject callScript(String path, String module, String method) { /*PythonInterpreter interpreter = new PythonInterpreter(); interpreter.cleanup(); interpreter.exec("import sys\nsys.path.append('" + path + "')\nfrom " + module + " import " + method); @@ -46,10 +46,10 @@ public class ScriptService { func.__call__(Py.java2py(core));*/ PythonInterpreter python = new PythonInterpreter(); python.execfile(path + module + ".py"); - python.get(method).__call__(); + return python.get(method).__call__(); } - public void callScript(String path, String module, String method, Object arg1) { + public PyObject callScript(String path, String module, String method, Object arg1) { /*PythonInterpreter interpreter = new PythonInterpreter(); interpreter.cleanup(); interpreter.exec("import sys\nsys.path.append('" + path + "')\nfrom " + module + " import " + method); @@ -57,10 +57,10 @@ public class ScriptService { func.__call__(Py.java2py(core), Py.java2py(arg1));*/ PythonInterpreter python = new PythonInterpreter(); python.execfile(path + module + ".py"); - python.get(method).__call__(Py.java2py(arg1)); + return python.get(method).__call__(Py.java2py(arg1)); } - public void callScript(String path, String method, String module, Object arg1, Object arg2) { + public PyObject callScript(String path, String method, String module, Object arg1, Object arg2) { /*PythonInterpreter interpreter = new PythonInterpreter(); interpreter.cleanup(); interpreter.exec("import sys\nsys.path.append('" + path + "')\nfrom " + module + " import " + method); @@ -68,10 +68,10 @@ public class ScriptService { func.__call__(Py.java2py(arg1), Py.java2py(arg2));*/ PythonInterpreter python = new PythonInterpreter(); python.execfile(path + module + ".py"); - python.get(method).__call__(Py.java2py(arg1), Py.java2py(arg2)); + return python.get(method).__call__(Py.java2py(arg1), Py.java2py(arg2)); } - public void callScript(String path, String method, String module, Object arg1, Object arg2, Object arg3) { + public PyObject callScript(String path, String method, String module, Object arg1, Object arg2, Object arg3) { /*PythonInterpreter interpreter = new PythonInterpreter(); interpreter.cleanup(); interpreter.exec("import sys\nsys.path.append('" + path + "')\nfrom " + module + " import " + method); @@ -79,11 +79,11 @@ public class ScriptService { func.__call__(Py.java2py(arg1), Py.java2py(arg2), Py.java2py(arg3));*/ PythonInterpreter python = new PythonInterpreter(); python.execfile(path + module + ".py"); - python.get(method).__call__(Py.java2py(arg1), Py.java2py(arg2), Py.java2py(arg3)); + return python.get(method).__call__(Py.java2py(arg1), Py.java2py(arg2), Py.java2py(arg3)); } - public void callScript(String path, String module, String method, Object arg1, Object arg2, Object arg3, Object arg4) { + public PyObject callScript(String path, String module, String method, Object arg1, Object arg2, Object arg3, Object arg4) { /*PythonInterpreter interpreter = new PythonInterpreter(); interpreter.cleanup(); interpreter.exec("import sys\nsys.path.append('" + path + "')\nfrom " + module + " import " + method); @@ -91,14 +91,13 @@ public class ScriptService { func.__call__(Py.java2py(arg1), Py.java2py(arg2), Py.java2py(arg3), Py.java2py(arg4));*/ PythonInterpreter python = new PythonInterpreter(); python.execfile(path + module + ".py"); - python.get(method).__call__(Py.java2py(arg1), Py.java2py(arg2), Py.java2py(arg3), Py.java2py(arg4)); + return python.get(method).__call__(Py.java2py(arg1), Py.java2py(arg2), Py.java2py(arg3), Py.java2py(arg4)); } public PyObject getMethod(String path, String module, String method) { - PythonInterpreter interpreter = new PythonInterpreter(); - interpreter.cleanup(); - interpreter.exec("import sys\nsys.path.append('" + path + "')\nfrom " + module + " import " + method); - PyObject func = interpreter.get(method); + PythonInterpreter python = new PythonInterpreter(); + python.execfile(path + module + ".py"); + PyObject func = python.get(method); return func; } diff --git a/src/services/SimulationService.java b/src/services/SimulationService.java index 83b80a8a..1bea2435 100644 --- a/src/services/SimulationService.java +++ b/src/services/SimulationService.java @@ -138,6 +138,8 @@ public class SimulationService implements INetworkDispatch { core.commandService.registerCommand("deathblow"); core.commandService.registerCommand("endduel"); core.commandService.registerCommand("duel"); + core.commandService.registerCommand("purchaseticket"); + core.commandService.registerCommand("boardshuttle"); } @@ -548,7 +550,14 @@ public class SimulationService implements INetworkDispatch { } } } - + + if (!object.hasSkill(ghost.getProfessionWheelPosition())) { + object.showFlyText("cbt_spam", "skill_up", (float) 2.5, new RGB(154, 205, 50), 0); + object.playEffectObject("clienteffect/skill_granted.cef", ""); + object.playMusic("sound/music_acq_bountyhunter.snd"); + core.skillService.addSkill(object, ghost.getProfessionWheelPosition()); + } + } public void transferToPlanet(SWGObject object, Planet planet, Point3D newPos, Quaternion newOrientation, SWGObject newParent) { diff --git a/src/services/SkillModService.java b/src/services/SkillModService.java index 6ca47aa9..d84576b0 100644 --- a/src/services/SkillModService.java +++ b/src/services/SkillModService.java @@ -23,10 +23,10 @@ package services; import java.util.Map; +import resources.objects.SWGList; import resources.objects.creature.CreatureObject; - import main.NGECore; - +import engine.resources.objects.SkillMod; import engine.resources.service.INetworkDispatch; import engine.resources.service.INetworkRemoteEvent; @@ -49,6 +49,22 @@ public class SkillModService implements INetworkDispatch { core.scriptService.callScript("scripts/skillMods/", skillMod, "deduct", core, creature, skillMod, value); } + + public boolean hasSkillMod(CreatureObject creature, String skillMod) { + + SWGList skillMods = creature.getSkillMods(); + + if (skillMods.isEmpty()) { return false; } + + for (SkillMod skill : skillMods) { + if (skill.getSkillModString() == skillMod) { + return true; + } + else { return false; } + } + + return false; + } @Override public void insertOpcodes(Map arg0, Map arg1) { diff --git a/src/services/SkillService.java b/src/services/SkillService.java new file mode 100644 index 00000000..7d3a358d --- /dev/null +++ b/src/services/SkillService.java @@ -0,0 +1,228 @@ +/******************************************************************************* + * Copyright (c) 2013 + * + * This File is part of NGECore2. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Using NGEngine to work with NGECore2 is making a combined work based on NGEngine. + * Therefore all terms and conditions of the GNU Lesser General Public License cover the combination. + ******************************************************************************/ +package services; + +import java.util.Map; + +import resources.objects.creature.CreatureObject; +import resources.objects.player.PlayerObject; + +import main.NGECore; + +import engine.clientdata.ClientFileManager; +import engine.clientdata.visitors.DatatableVisitor; +import engine.resources.service.INetworkDispatch; +import engine.resources.service.INetworkRemoteEvent; + +public class SkillService implements INetworkDispatch { + + private NGECore core; + + public SkillService(NGECore core) { + this.core = core; + } + + public void addSkill(CreatureObject creature, String skill) { + PlayerObject player = (PlayerObject) creature.getSlottedObject("ghost"); + DatatableVisitor skillTable; + + if (player == null) { + return; + } + + if (creature.hasSkill(skill)) { + return; + } + + try { + skillTable = ClientFileManager.loadFile("datatables/skill/skills.iff", DatatableVisitor.class); + + for (int s = 0; s < skillTable.getRowCount(); s++) { + if (skillTable.getObject(s, 0) != null) { + if (((String) skillTable.getObject(s, 0)).equals(skill)) { + //String parent = ((String) skillTable.getObject(s, 1)); + //int graphType = ((Integer) skillTable.getObject(s, 2)); + boolean godOnly = ((Boolean) skillTable.getObject(s, 3)); + //boolean isTitle = ((Boolean) skillTable.getObject(s, 4)); + boolean isProfession = ((Boolean) skillTable.getObject(s, 5)); + boolean isHidden = ((Boolean) skillTable.getObject(s, 6)); + int pointsRequired = ((Integer) skillTable.getObject(s, 8)); + int skillsRequiredCount = ((Integer) skillTable.getObject(s, 9)); + String[] skillsRequired = ((String) skillTable.getObject(s, 10)).split(","); + String[] preclusionSkills = ((String) skillTable.getObject(s, 11)).split(","); + String xpType = ((String) skillTable.getObject(s, 12)); + int xpCost = ((Integer) skillTable.getObject(s, 13)); + //int xpCap = ((Integer) skillTable.getObject(s, 14)); + String[] statsRequired = ((String) skillTable.getObject(s, 17)).split(","); + String speciesRequired = (String) skillTable.getObject(s, 18); + String[] abilities = ((String) skillTable.getObject(s, 21)).split(","); + String[] skillMods = ((String) skillTable.getObject(s, 22)).split(","); + String[] schematicsGranted = ((String) skillTable.getObject(s, 23)).split(","); + String[] schematicsRevoked = ((String) skillTable.getObject(s, 24)).split(","); + + if (isProfession) { + return; + } + + if (godOnly || isHidden) { + return; + } + + if (pointsRequired > 0) { + //if (creature.getExpertisePoints() > pointsRequired) { + //creature.deductExpertisePoints(pointsRequired); + //} else { + //return; + //} + } + + if (creature.getSkills().size() < skillsRequiredCount) { + return; + } + + for (String skillName : skillsRequired) { + if (skillName != "" && !creature.hasSkill(skillName)) { + System.out.println("Skill Name: " + skillName); + return; + } + } + + for (String skillName : preclusionSkills) { + if (creature.hasSkill(skillName)) { + return; + } + } + + for (String stat : statsRequired) { + if ((stat != "") && (creature.getSkillMod(stat) == null || creature.getSkillMod(stat).getBase() < 1)) { + return; + } + } + + if (!creature.getStfName().contains(speciesRequired)) { + return; + } + + if (xpType != null || xpType != "") { + if (xpCost > 0) { + if (player.getXp(xpType) >= xpCost) { + //player.setXp(xpType, (player.getXp(xpType) - xpCost)); + } else { + //return; + } + } + } + + for (String ability : abilities) { + creature.addAbility(ability); + } + + for (String skillMod : skillMods) { + if (skillMod != "" && skillMod != null && skillMod.contains("=")) { + core.skillModService.addSkillMod(creature, skillMod.split("=")[0], new Integer(skillMod.split("=")[1])); + } + } + + for (String schematic : schematicsGranted) { + //player.getDraftSchematicList().add(new DraftSchematic()); + } + + for (String schematic : schematicsRevoked) { + //player.getDraftSchematicList().remove(new DraftSchematic()); + } + + creature.addSkill(skill); + } + } + } + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + public void removeSkill(CreatureObject creature, String skill) { + PlayerObject player = (PlayerObject) creature.getSlottedObject("ghost"); + DatatableVisitor skillTable; + + if (creature.getClient() == null) { + return; + } + + if (!creature.hasSkill(skill)) { + return; + } + + try { + skillTable = ClientFileManager.loadFile("datatables/skills/skills.iff", DatatableVisitor.class); + + for (int s = 0; s < skillTable.getRowCount(); s++) { + if (skillTable.getObject(s, 0) != null) { + if (((String) skillTable.getObject(s, 0)).equals(skill)) { + String parent = ((String) skillTable.getObject(s, 1)); + //int graphType = ((Integer) skillTable.getObject(s, 2)); + boolean godOnly = ((Boolean) skillTable.getObject(s, 3)); + //boolean isTitle = ((Boolean) skillTable.getObject(s, 4)); + boolean isHidden = ((Boolean) skillTable.getObject(s, 6)); + int pointsRequired = ((Integer) skillTable.getObject(s, 8)); + String[] abilities = ((String) skillTable.getObject(s, 21)).split(","); + String[] skillMods = ((String) skillTable.getObject(s, 22)).split(","); + String[] schematicsGranted = ((String) skillTable.getObject(s, 23)).split(","); + String[] schematicsRevoked = ((String) skillTable.getObject(s, 24)).split(","); + + if (pointsRequired > 0) { + //creature.addExpertisePoints(pointsRequired); + } + + for (String ability : abilities) { + creature.removeAbility(ability); + } + + for (String skillMod : skillMods) { + core.skillModService.deductSkillMod(creature, skillMod.split("=")[0], new Integer(skillMod.split("=")[1])); + } + + for (String schematic : schematicsGranted) { + //player.getDraftSchematicList().remove(new DraftSchematic()); + } + + for (String schematic : schematicsRevoked) { + //player.getDraftSchematicList().add(new DraftSchematic()); + } + } + } + } + } catch (InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public void insertOpcodes(Map arg0, Map arg1) { + + } + + @Override + public void shutdown() { + + } + +} diff --git a/src/services/combat/CombatService.java b/src/services/combat/CombatService.java index 08ac32e3..fc2bf692 100644 --- a/src/services/combat/CombatService.java +++ b/src/services/combat/CombatService.java @@ -43,7 +43,6 @@ import protocol.swg.objectControllerObjects.StartTask; import resources.common.FileUtilities; import resources.objects.Buff; import resources.objects.DamageOverTime; -import resources.objects.cell.CellObject; import resources.objects.creature.CreatureObject; import resources.objects.player.PlayerObject; import resources.objects.tangible.TangibleObject; diff --git a/src/services/command/CommandService.java b/src/services/command/CommandService.java index 0bee3a29..9d8a4487 100644 --- a/src/services/command/CommandService.java +++ b/src/services/command/CommandService.java @@ -152,6 +152,13 @@ public class CommandService implements INetworkDispatch { public void processCombatCommand(CreatureObject attacker, SWGObject target, CombatCommand command, int actionCounter, String commandArgs) { + // Check if the person has access to this ability. + // Abilities (inc expertise ones) are added automatically as they level + // by reading the datatables. + if (!attacker.hasAbility(command.getCommandName())) { + return; + } + if(FileUtilities.doesFileExist("scripts/commands/combat/" + command.getCommandName() + ".py")) core.scriptService.callScript("scripts/commands/combat/", command.getCommandName(), "setup", core, attacker, target, command); @@ -213,7 +220,7 @@ public class CommandService implements INetworkDispatch { if(target != attacker && success && !core.simulationService.checkLineOfSight(attacker, target)) { - ShowFlyText los = new ShowFlyText(attacker.getObjectID(), attacker.getObjectID(), "combat_effects", "cant_see", (float) 1.5, (float) 429664.031250); + ShowFlyText los = new ShowFlyText(attacker.getObjectID(), attacker.getObjectID(), "combat_effects", "cant_see", (float) 1.5, new RGB(72, 209, 204), 1); ObjControllerMessage objController = new ObjControllerMessage(0x1B, los); attacker.getClient().getSession().write(objController.serialize()); success = false; @@ -243,6 +250,18 @@ public class CommandService implements INetworkDispatch { } + public void callCommand(CreatureObject actor, String commandName, SWGObject target, String commandArgs) { + if (actor == null) + return; + + BaseSWGCommand command = getCommandByName(commandName); + + if (command == null) + return; + + core.scriptService.callScript("scripts/commands/", command.getCommandName(), "run", core, actor, target, commandArgs); + System.out.println("Script called."); + } @Override public void shutdown() { diff --git a/src/services/object/ObjectService.java b/src/services/object/ObjectService.java index ff26417b..ca26549a 100644 --- a/src/services/object/ObjectService.java +++ b/src/services/object/ObjectService.java @@ -77,6 +77,7 @@ import resources.objects.staticobject.StaticObject; import resources.objects.tangible.TangibleObject; import resources.objects.waypoint.WaypointObject; import resources.objects.weapon.WeaponObject; +import services.travel.ShuttleObject; @SuppressWarnings("unused") @@ -142,7 +143,11 @@ public class ObjectService implements INetworkDispatch { if(objectID == 0) objectID = generateObjectID(); - if(Template.startsWith("object/creature")) { + if(Template.equals(ShuttleObject.ShuttleType.CIVILIAN.toString()) || Template.equals(ShuttleObject.ShuttleType.STARSHIP.toString()) || + Template.equals(ShuttleObject.ShuttleType.THEED.toString())) { + object = new ShuttleObject(objectID, planet, position, orientation, Template); + + } else if(Template.startsWith("object/creature")) { object = new CreatureObject(objectID, planet, position, orientation, Template); @@ -182,7 +187,7 @@ public class ObjectService implements INetworkDispatch { object = new WaypointObject(objectID, planet, position); - } else { + } else { return null; diff --git a/src/services/object/ObjectTransactionManager.java b/src/services/object/ObjectTransactionManager.java index caba44ec..f4fcfc6a 100644 --- a/src/services/object/ObjectTransactionManager.java +++ b/src/services/object/ObjectTransactionManager.java @@ -23,7 +23,6 @@ package services.object; import java.util.Collection; import java.util.Iterator; -import java.util.List; import com.sleepycat.je.Transaction; diff --git a/src/services/travel/ShuttleObject.java b/src/services/travel/ShuttleObject.java new file mode 100644 index 00000000..c7095076 --- /dev/null +++ b/src/services/travel/ShuttleObject.java @@ -0,0 +1,79 @@ +package services.travel; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import engine.resources.scene.Planet; +import engine.resources.scene.Point3D; +import engine.resources.scene.Quaternion; +import resources.objects.creature.CreatureObject; + +public class ShuttleObject extends CreatureObject { + + private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + private boolean isInPort; + private int nextShuttleTime; + + + public ShuttleObject(long objectID, Planet planet, Point3D position, Quaternion orientation, String Template) { + super(objectID, planet, position, orientation, Template); + scheduleShuttle(); + } + + public ShuttleObject() { + super(); + } + + public void scheduleShuttle() { + final Runnable myRunnable = new Runnable() { + @Override + public void run() { + if (isInPort) { + setPosture((byte) 2); + isInPort = false; + nextShuttleTime = 60; + } else { + setPosture((byte) 0); + isInPort = true; + nextShuttleTime = 0; + } + } + }; + + scheduler.scheduleAtFixedRate(myRunnable, 60, 60, TimeUnit.SECONDS); + } + + public enum ShuttleType { + STARSHIP, + CIVILIAN, + THEED; + + @Override + public String toString() { + switch(this) { + case CIVILIAN: + return "object/creature/npc/theme_park/shared_player_shuttle.iff"; + case STARSHIP: + return "object/creature/npc/theme_park/shared_player_transport.iff"; + case THEED: + return "object/creature/npc/theme_park/shared_player_transport_theed_hangar.iff"; + default: + return "object/creature/npc/theme_park/shared_player_shuttle.iff"; + + } + } + } + + public ScheduledExecutorService getSchedule() { + return scheduler; + } + + public boolean isInPort() { + return this.isInPort; + } + + public int getNextShuttleTime() { + return this.nextShuttleTime; + } +} diff --git a/src/services/travel/TravelPoint.java b/src/services/travel/TravelPoint.java index ae314aa9..b1cb8756 100644 --- a/src/services/travel/TravelPoint.java +++ b/src/services/travel/TravelPoint.java @@ -21,22 +21,26 @@ ******************************************************************************/ package services.travel; +import resources.common.SpawnPoint; +import engine.resources.scene.Point3D; + public class TravelPoint { + private String planetName; private String name; - private float posX; - private float posY; - private float posZ; + private Point3D location; + private SpawnPoint spawnLocation; private int ticketPrice; + private ShuttleObject shuttleObject; public TravelPoint() { } public TravelPoint(String name, float x, float y, float z, int price) { this.name = name; - this.posX = x; - this.posY = y; - this.posZ = z; + this.location = new Point3D(x, y, z); + this.spawnLocation = new SpawnPoint(this.location, 0, 1); + this.shuttleObject = new ShuttleObject(); } public String getName() { @@ -45,28 +49,45 @@ public class TravelPoint { public void setName(String name) { this.name = name; } - public float getPosX() { - return posX; + + public Point3D getLocation() { + return location; } - public void setPosX(float posX) { - this.posX = posX; - } - public float getPosY() { - return posY; - } - public void setPosY(float posY) { - this.posY = posY; - } - public float getPosZ() { - return posZ; - } - public void setPosZ(float posZ) { - this.posZ = posZ; + + public void setLocation(float x, float y, float z) { + this.location.x = x; + this.location.y = y; + this.location.z = z; } + public int getTicketPrice() { return ticketPrice; } public void setTicketPrice(int ticketPrice) { this.ticketPrice = ticketPrice; } + + public String getPlanetName() { + return planetName; + } + + public void setPlanetName(String planetName) { + this.planetName = planetName; + } + + public SpawnPoint getSpawnLocation() { + return this.spawnLocation; + } + + public void setSpawnLocation(SpawnPoint point) { + this.spawnLocation = point; + } + + public ShuttleObject getShuttle() { + return this.shuttleObject; + } + + public void setShuttle(ShuttleObject shuttleObj) { + this.shuttleObject = shuttleObj; + } } diff --git a/src/services/travel/TravelService.java b/src/services/travel/TravelService.java index 02f3c724..153452ef 100644 --- a/src/services/travel/TravelService.java +++ b/src/services/travel/TravelService.java @@ -22,29 +22,44 @@ package services.travel; import java.nio.ByteOrder; +import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Vector; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import org.apache.commons.lang3.text.WordUtils; import org.apache.mina.core.buffer.IoBuffer; import org.apache.mina.core.session.IoSession; import protocol.swg.PlanetTravelPointListRequest; import protocol.swg.PlanetTravelPointListResponse; import engine.clients.Client; +import engine.resources.container.Traverser; import engine.resources.objects.SWGObject; import engine.resources.scene.Planet; +import engine.resources.scene.Point3D; +import engine.resources.scene.quadtree.QuadTree; import engine.resources.service.INetworkDispatch; import engine.resources.service.INetworkRemoteEvent; import main.NGECore; import resources.common.Opcodes; +import resources.objects.creature.CreatureObject; +import resources.objects.player.PlayerObject; +import resources.objects.tangible.TangibleObject; import services.map.*; +import services.sui.SUIService.ListBoxType; +import services.sui.SUIWindow.SUICallback; +import services.sui.SUIWindow.Trigger; +import services.sui.SUIWindow; public class TravelService implements INetworkDispatch { private NGECore core; - private Map> travelMap = new ConcurrentHashMap>(); + private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); public TravelService(NGECore core) { this.core = core; @@ -72,25 +87,75 @@ public class TravelService implements INetworkDispatch { if(object == null) return; - PlanetTravelPointListResponse response = new PlanetTravelPointListResponse(request.getPlanet(), travelMap.get(request.getPlanet())); - client.getSession().write(response.serialize()); + List planetList = core.terrainService.getPlanetList(); + for (Planet planet : planetList) { + String planetString = planet.getName(); + + if (request.getPlanet().equals(planetString)) { + + PlanetTravelPointListResponse response = new PlanetTravelPointListResponse(planetString, travelMap.get(planet), planetList); + client.getSession().write(response.serialize()); + break; + + } + } } - }); } + public TravelPoint getNearestTravelPoint() { + TravelPoint returnedPoint = null; + + + return returnedPoint; + } + + public TravelPoint getTravelPointByName(String planet, String tpName) { + Planet planetObj = core.terrainService.getPlanetByName(planet.toLowerCase()); + + Vector tpMap = travelMap.get(planetObj); + + TravelPoint returnedPoint = null; + + for (TravelPoint tp : tpMap) { + if (tp.getName().equals(tpName)) { + returnedPoint = tp; + } + } + if (returnedPoint == null) { System.out.println("Couldn't find a travelpoint w/ name " + tpName); } + return returnedPoint; + } + public void addPlanet(Planet planet) { Vector travelPointVector = new Vector(); travelMap.put(planet, travelPointVector); + core.scriptService.callScript("scripts/", "addPoints", "static_travel_points", core, planet); } - - public void addTravelPoint(Planet planet, String name, float x, float y, float z) { - TravelPoint travelPoint = new TravelPoint(name, x, y, z, 100); + public void addShuttleToPoint(SWGObject obj) { + Vector travelPoints = travelMap.get(obj.getPlanet()); - if (travelMap.get(planet) != null) { + for (TravelPoint tp : travelPoints) { + float distancePoint = tp.getLocation().getDistance2D(obj.getPosition()); + System.out.println("Distance from point " + tp.getName() + ": " + distancePoint); + + // Travel points must be within 50 meters of shuttles! + if (distancePoint <= (float) 50) { + tp.setShuttle((ShuttleObject) obj); + } + + } + } + + public void addTravelPoint(Planet planet, String name, float x, float y, float z) { + // z should be y for 2d map + TravelPoint travelPoint = new TravelPoint(name, x, y, z, 100); + + travelPoint.setPlanetName(WordUtils.capitalize(planet.getName())); + + if (travelMap.containsKey(planet)) { travelMap.get(planet).add(travelPoint); System.out.println("Added travel point " + travelPoint.getName()); @@ -99,9 +164,145 @@ public class TravelService implements INetworkDispatch { Vector travelPointVector = new Vector(); travelMap.put(planet, travelPointVector); travelMap.get(planet).add(travelPoint); - System.out.println("Added planet " + planet.getName() + " with travel point: " + travelPoint.getName()); + System.out.println("Added planet " + planet.getName() + " to TravelMap."); + System.out.println("Added travel point " + travelPoint.getName()); + } + } + + public void removeTravelPointByName(Planet planet, String name){ + if (travelMap.containsKey(planet)) { + Vector travelVector = travelMap.get(planet); + + for(TravelPoint point : travelVector) { + if (point.getName() == name) { + travelMap.get(planet).removeElement(point); + break; + } + } + } + } + + public void loadTravelPoints() { + List planetList = core.terrainService.getPlanetList(); + for (Planet planet : planetList) { + addPlanet(planet); + } + } + + public SWGObject createTravelTicket(String departurePlanet, String departureLoc, String arrivalPlanet, String arrivalLoc) { + + Planet planet = core.terrainService.getPlanetByName(departurePlanet.toLowerCase()); + SWGObject travelTicket = core.objectService.createObject("object/tangible/travel/travel_ticket/base/shared_base_travel_ticket.iff", planet); + + travelTicket.setStringAttribute("@obj_attr_n:travel_departure_planet", WordUtils.capitalize(departurePlanet)); + travelTicket.setStringAttribute("@obj_attr_n:travel_departure_point", departureLoc); + + travelTicket.setStringAttribute("@obj_attr_n:travel_arrival_planet", WordUtils.capitalize(arrivalPlanet)); + travelTicket.setStringAttribute("@obj_attr_n:travel_arrival_point", arrivalLoc); + + travelTicket.setAttachment("objType", "ticket"); + System.out.println("Object type: " + travelTicket.getAttachment("objType")); + + return travelTicket; + } + + public void purchaseTravelTicket(SWGObject player, String departurePlanet, String departureLoc, String arrivalPlanet, String arrivalLoc) { + CreatureObject creatureObj = (CreatureObject) player; + + SWGObject travelTicket = createTravelTicket(departurePlanet, departureLoc, arrivalPlanet, arrivalLoc); + + creatureObj.getSlottedObject("inventory").add(travelTicket); + travelTicket.isSubChildOf(player); + + creatureObj.sendSystemMessage("@travel:ticket_purchase_complete", (byte) 0); + System.out.println("Created travel ticket: " + departurePlanet + " " + departureLoc + " " + arrivalPlanet + " " + arrivalLoc); + } + + // This returns all ticket objects in a players inventory + public Vector getTicketList(SWGObject player) { + + final Vector ticketList = new Vector(); + + TangibleObject playerInventory = (TangibleObject) player.getSlottedObject("inventory"); + + playerInventory.viewChildren(player, false, false, new Traverser() { + // ^-topDown-^-recursive + // topDown - If true, objects that are at the top of the tree are viewed first. + // the "viewer" needs to be whatever object wants to know this information (player) + @Override + public void process(SWGObject obj) { + if (obj.getAttachment("objType") != null) { + String objType = (String) obj.getAttachment("objType"); + String ticket = "ticket"; + if (objType.equals(ticket)) { + ticketList.add(obj); + } + } + } + }); + return ticketList; + } + + // TravelPoint = the travelpoint player is going to travel to! + public void doTransport(SWGObject actor, TravelPoint tp) { + + if (tp.getPlanetName().toLowerCase().equals(actor.getPlanet().name)) { + core.simulationService.teleport(actor, tp.getSpawnLocation().getPosition(), tp.getSpawnLocation().getOrientation(), 0); + } + + else { core.simulationService.transferToPlanet(actor, core.terrainService.getPlanetByName(tp.getPlanetName()), tp.getSpawnLocation().getPosition(), tp.getSpawnLocation().getOrientation(), actor); } + } + + + public void sendTicketWindow(final CreatureObject creature) { + + if (creature == null) + return; + + Map ticketData = new HashMap(); + Vector invTickets = getTicketList(creature); + + for (SWGObject ticket : invTickets) { + ticketData.put(ticket.getObjectId(), ticket.getStringAttribute("@obj_attr_n:travel_arrival_planet") + " -- " + + ticket.getStringAttribute("@obj_attr_n:travel_arrival_point")); } + final SUIWindow window = core.suiService.createListBox(ListBoxType.LIST_BOX_OK_CANCEL, "Select Destination", "Select Destination", ticketData, creature, null, 0); + Vector returnList = new Vector(); + returnList.add("List.lstList:SelectedRow"); + + window.addHandler(0, "", Trigger.TRIGGER_OK, returnList, new SUICallback() { + + @Override + public void process(SWGObject owner, int eventType, Vector returnList) { + // return list = int number of selected row + int index = Integer.parseInt(returnList.get(0)); + + SWGObject selectedTicket = core.objectService.getObject(window.getObjectIdByIndex(index)); + System.out.println("Selected ticket obj: " + window.getObjectIdByIndex(index)); + + TravelPoint arrivalPoint = getTravelPointByName(selectedTicket.getStringAttribute("@obj_attr_n:travel_arrival_planet").toLowerCase(), + selectedTicket.getStringAttribute("@obj_attr_n:travel_arrival_point")); + + TravelPoint departurePoint = getTravelPointByName(creature.getPlanet().name, selectedTicket.getStringAttribute("@obj_attr_n:travel_departure_point")); + + if (departurePoint.getShuttle() == null) { + System.out.println("TravelPoint has no associated shuttle!"); + return; + } + + if (departurePoint.getShuttle().isInPort()) { + selectedTicket.getContainer().remove(selectedTicket); + core.objectService.destroyObject(selectedTicket); + doTransport(creature, arrivalPoint); + } + else { + creature.sendSystemMessage("The next shuttle arrives in " + departurePoint.getShuttle().getNextShuttleTime() + " seconds.", (byte) 0); + } + } + }); + + core.suiService.openSUIWindow(window); }