diff --git a/motd.txt b/motd.txt new file mode 100644 index 00000000..8d8e4743 --- /dev/null +++ b/motd.txt @@ -0,0 +1 @@ +Welcome to the ProjectSWG TestCenter! \ No newline at end of file diff --git a/nge.cfg b/nge.cfg index 036d6202..b11b4219 100644 --- a/nge.cfg +++ b/nge.cfg @@ -13,4 +13,3 @@ GALAXY_ID=2 GALAXY_NAME=Local Connection XPMULTIPLIER=1.0 MAXNUMBEROFCHARACTERS=2 -MOTD=Welcome to PSWG Test Center! \ No newline at end of file diff --git a/scripts/commands/guild.py b/scripts/commands/guild.py index f779ef28..2bc6b552 100644 --- a/scripts/commands/guild.py +++ b/scripts/commands/guild.py @@ -7,9 +7,7 @@ def run(core, actor, target, commandString): guild = core.guildService.getGuildById(actor.getGuildId()) if guild is None: - print ('none.') return core.chatService.sendChatRoomMessage(actor, guild.getChatRoomId(), 0, commandString) - print ('sent message') return \ No newline at end of file diff --git a/scripts/commands/guilddisband.py b/scripts/commands/guilddisband.py new file mode 100644 index 00000000..8f0e6124 --- /dev/null +++ b/scripts/commands/guilddisband.py @@ -0,0 +1,26 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + + if actor.getGuildId() == 0: + return + + guildSvc = core.guildService + + guild = guildSvc.getGuildById(actor.getGuildId()) + + if guild is None: + return + + member = guild.getMember(actor.getObjectID()) + if actor.getObjectID() != guild.getLeader() and member.hasDisbandPermission() is False: + actor.sendSystemMessage('@guild:guild_no_permission_operation', 0) + return + else: + guildSvc.showDisbandConfirmWindow(actor, target, guild) + return + + return diff --git a/scripts/commands/guildremove.py b/scripts/commands/guildremove.py new file mode 100644 index 00000000..f974c160 --- /dev/null +++ b/scripts/commands/guildremove.py @@ -0,0 +1,36 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + + if commandString != " " and commandString != "": + target = core.objectService.getObjectByFirstName(commandString.split(" ")[0]) + + if target is None: + actor.sendSystemMessage('Could not find member ' + commandString + ' (CASE SENSITIVE!)', 0) + return + + if actor.getGuildId() == 0: + return + + if actor.getGuildId() != target.getGuildId(): + actor.sendSystemMessage('@guild:guild_no_permission_operation', 0) + return + + guildSvc = core.guildService + + guild = guildSvc.getGuildById(actor.getGuildId()) + + if guild is None: + return + + if actor.getObjectID() == target.getObjectID(): + guildSvc.leaveGuild(actor, target, guild) + return + else: + guildSvc.showKickConfirmWindow(actor, target, guild) + return + + return diff --git a/scripts/commands/guildsponsor.py b/scripts/commands/guildsponsor.py new file mode 100644 index 00000000..513af1ed --- /dev/null +++ b/scripts/commands/guildsponsor.py @@ -0,0 +1,28 @@ +import sys + +def setup(): + return + +def run(core, actor, target, commandString): + + if actor.getGuildId() == 0: + return + + guildSvc = core.guildService + + guild = guildSvc.getGuildById(actor.getGuildId()) + + if guild is None: + return + + member = guild.getMember(actor.getObjectID()) + + if member is None: + return + + if not member.hasSponsorPermission(): + actor.sendSystemMessage('@guild:guild_no_permission_operation', 0) + return + + guildSvc.handleGuildSponsorWindow(actor) + return diff --git a/scripts/radial/object/guild_access_device.py b/scripts/radial/object/guild_access_device.py index a29ec5e3..09e3d899 100644 --- a/scripts/radial/object/guild_access_device.py +++ b/scripts/radial/object/guild_access_device.py @@ -25,27 +25,26 @@ def createRadial(core, owner, target, radials): radials.add(RadialOptions(0, RadialOptions.serverGuildGuildManagement, 3, '@guild:menu_guild_management')) # Guild Management radials.add(RadialOptions(0, RadialOptions.serverGuildMemberManagement, 3, '@guild:menu_member_management')) # Member Management - # Guild Management + #### Guild Management #### radials.add(RadialOptions(3, RadialOptions.serverGuildInfo, 3, '@guild:menu_info')) # Guild Information #radials.add(RadialOptions(3, RadialOptions.serverGuildEnemies, 3, '@guild:menu_enemies')) # Guild Enemies #radials.add(RadialOptions(3, 215, 3, '@guild:menu_rank_list')) # Rank List # TODO: Add Rank Summary radials.add(RadialOptions(3, 217, 3, '@guild:menu_permission_list')) # Permissions List - #if member.hasDisbandPermission(): - #radials.add(RadialOptions(3, RadialOptions.serverGuildDisband, 3, '@guild:menu_disband')) # Disband Guild + if member.hasDisbandPermission(): + radials.add(RadialOptions(3, RadialOptions.serverGuildDisband, 3, '@guild:menu_disband')) # Disband Guild #if member.hasChangeNamePermission(): #radials.add(RadialOptions(3, RadialOptions.serverGuildNameChange, 3, '@guild:menu_namechange')) - #if owner.getObjectID() == guild.getLeader(): - #radials.add(RadialOptions(4, RadialOptions.serverTerminalPermissions, 3, '@guild:menu_permission_list')) # Permission List - # Member Management - #radials.add(RadialOptions(4, RadialOptions.serverGuildMembers, 3, '@guild:menu_members')) # Guild Members + #### Member Management #### + radials.add(RadialOptions(4, RadialOptions.serverGuildMembers, 3, '@guild:menu_members')) # Guild Members if member.hasSponsorPermission(): radials.add(RadialOptions(4, RadialOptions.serverGuildSponsor, 3, '@guild:menu_sponsor')) # Sponsor for Membership if member.hasAcceptPermission() and guild.getSponsoredPlayers().size() > 0: radials.add(RadialOptions(4, RadialOptions.serverGuildSponsored, 3, '@guild:menu_sponsored')) # Sponsored for Membership - #if owner.getObjectID() == guild.getLeader(): + if owner.getObjectID() == guild.getLeader(): + radials.add(RadialOptions(4, 218, 3, '@guild:menu_member_motd')) # Create a Guild Message #radials.add(RadialOptions(4, 69, 3, '@guild:menu_leader_change')) # Transfer PA Leadership return @@ -57,7 +56,7 @@ def handleSelection(core, owner, target, option): if guild is None: return - # Guild Management + #### Guild Management #### # - Guild Info if option == RadialOptions.serverGuildInfo: @@ -81,15 +80,20 @@ def handleSelection(core, owner, target, option): core.guildService.handleViewPermissionsList(owner, guild) return - # Member Management + elif option == RadialOptions.serverGuildDisband: + core.guildService.showDisbandConfirmWindow(owner, guild) + return + + #### Member Management #### # - Guild Members elif option == RadialOptions.serverGuildMembers: + core.guildService.handleViewGuildMembers(owner, guild) return # - Sponsor for Membership elif option == RadialOptions.serverGuildSponsor: - core.guildService.handleGuildSponsor(owner) + core.guildService.handleGuildSponsorWindow(owner) return # - Sponsored for Membership @@ -101,4 +105,7 @@ def handleSelection(core, owner, target, option): elif option == 69: return + elif option == 218: + core.guildService.handleChangeGuildMotd(owner, guild) + return return \ No newline at end of file diff --git a/scripts/radial/object/guild_registry.py b/scripts/radial/object/guild_registry.py index ed8e10b9..4b751dec 100644 --- a/scripts/radial/object/guild_registry.py +++ b/scripts/radial/object/guild_registry.py @@ -5,46 +5,16 @@ from main import NGECore import sys def createRadial(core, owner, target, radials): - - #radials.clear() - + if owner.getGuildId() == 0: radials.add(RadialOptions(0, RadialOptions.serverGuildCreate, 3, '@guild:menu_create')) return - + return def handleSelection(core, owner, target, option): - suiSvc = NGECore().getInstance().suiService # Create Guild if option == 185 and target: - wndGuildCreate = core.suiService.createInputBox(InputBoxType.INPUT_BOX_OK_CANCEL, '@guild:create_name_title', '@guild:create_name_prompt', owner, owner, 0, handleGuildCreateName) - wndGuildCreate.setProperty("txtInput:MaxLength", "24"); - wndGuildCreate.setProperty("txtInput:NumericInteger", "false") - suiSvc.openSUIWindow(wndGuildCreate) - return - - return - -def handleGuildCreateName(owner, window, eventType, returnList): - suiSvc = NGECore().getInstance().suiService - if eventType == 0: - guildName = str(returnList.get(0)) - if guildName is not None: - owner.setAttachment('guildName', guildName) - wndGuildInitials = NGECore().getInstance().suiService.createInputBox(InputBoxType.INPUT_BOX_OK, '@guild:create_abbrev_title', '@guild:create_abbrev_prompt', owner, owner, 0, doGuildCreate) - wndGuildInitials.setProperty("txtInput:MaxLength", "4"); - wndGuildInitials.setProperty("txtInput:NumericInteger", "false") - suiSvc.openSUIWindow(wndGuildInitials) + core.guildService.handleCreateGuildName(owner, target) return return - -def doGuildCreate(owner, window, eventType, returnList): - core = NGECore().getInstance() - if eventType == 0: - guild = core.guildService.createGuild(str(returnList.get(0)), str(owner.getAttachment('guildName')), owner) - member = core.guildService.joinGuild(guild, owner, None) - if member is not None: - member.giveAllPermissions() - return - return \ No newline at end of file diff --git a/src/main/NGECore.java b/src/main/NGECore.java index 1da3308a..95a4ecb7 100644 --- a/src/main/NGECore.java +++ b/src/main/NGECore.java @@ -21,7 +21,10 @@ ******************************************************************************/ package main; +import java.io.BufferedReader; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; import java.io.IOException; import java.sql.PreparedStatement; import java.sql.SQLException; @@ -140,7 +143,7 @@ public class NGECore { private static NGECore instance; private Config config = null; - + private String motd = ""; private volatile boolean isShuttingDown = false; private long galacticTime = System.currentTimeMillis(); @@ -272,6 +275,12 @@ public class NGECore { System.out.println("Cleaned ODB Folders."); } + try(BufferedReader br = new BufferedReader(new FileReader("./motd.txt"))) { + for(String line; (line = br.readLine()) != null;) { + motd += line; + } + } catch (IOException e1) { e1.printStackTrace(); } + // Database databaseConnection = new DatabaseConnection(); databaseConnection.connect(config.getString("DB.URL"), config.getString("DB.NAME"), config.getString("DB.USER"), config.getString("DB.PASS"), "postgresql"); @@ -774,6 +783,12 @@ public class NGECore { auctionODB.close(); } - + public String getMotd() { + return motd; + } + + public void setMotd(String motd) { + this.motd = motd; + } } diff --git a/src/resources/guild/Guild.java b/src/resources/guild/Guild.java index 5fa0f8da..3ec417e7 100644 --- a/src/resources/guild/Guild.java +++ b/src/resources/guild/Guild.java @@ -22,10 +22,8 @@ package resources.guild; import java.io.Serializable; -import java.util.ArrayList; import java.util.Date; import java.util.HashMap; -import java.util.List; import java.util.Map; import main.NGECore; @@ -47,14 +45,14 @@ public class Guild extends Delta implements Serializable, Comparable { private String leaderName; private Map members = new HashMap(); private Map sponsoredPlayers = new HashMap(); + private String motd; + public Guild(int id, String abbreviation, String name, SWGObject leader) { this.id = id; this.abbreviation = abbreviation; this.name = name; this.leader = leader.getObjectID(); this.leaderName = leader.getCustomName(); - //this.members.add(leader.getObjectID()); - //this.sponsors.add(leader.getObjectID()); } public Guild() { } @@ -145,6 +143,14 @@ public class Guild extends Delta implements Serializable, Comparable { } } + public String getMotd() { + return motd; + } + + public void setMotd(String motd) { + this.motd = motd; + } + public Map getMembers() { return members; } diff --git a/src/resources/guild/GuildMember.java b/src/resources/guild/GuildMember.java index 1a374ebf..4c6b3bdd 100644 --- a/src/resources/guild/GuildMember.java +++ b/src/resources/guild/GuildMember.java @@ -28,10 +28,10 @@ import java.util.Vector; public class GuildMember { private long objectId; private long joinTime; - private String profession; + private String profession = ""; private short level; - private String rank; - private String name; + private String rank = ""; + private String name = ""; // TODO: These might have to be moved to a new GuildRank class depending on how permissions worked for NGE //this works for now... Lack of NGE Guild Rank guides makes re-creation difficult (Ranks introduced Game Update 8: http://swg.wikia.com/wiki/Game_Update_8) diff --git a/src/resources/objects/player/PlayerObject.java b/src/resources/objects/player/PlayerObject.java index 9988a5f8..2601857d 100644 --- a/src/resources/objects/player/PlayerObject.java +++ b/src/resources/objects/player/PlayerObject.java @@ -893,10 +893,10 @@ public class PlayerObject extends IntangibleObject implements Serializable { } public void addChannel(int roomId) { - getJoinedChatChannels().add(roomId); + getJoinedChatChannels().add((Integer) roomId); } - public void removeChannel(int roomId) { + public void removeChannel(Integer roomId) { if (getJoinedChatChannels().contains(roomId)) { getJoinedChatChannels().remove(roomId); } diff --git a/src/services/ConnectionService.java b/src/services/ConnectionService.java index 9baa6d0b..eed1f254 100644 --- a/src/services/ConnectionService.java +++ b/src/services/ConnectionService.java @@ -241,13 +241,6 @@ public class ConnectionService implements INetworkDispatch { core.chatService.playerStatusChange(objectShortName, (byte) 0); - for (Integer roomId : ghost.getJoinedChatChannels()) { - ChatRoom room = core.chatService.getChatRoom(roomId.intValue()); - - if (room != null) { core.chatService.leaveChatRoom(object, roomId.intValue()); } - // work-around for any channels that may have been deleted, or only spawn on server startup, that were added to the joined channels - else { ghost.removeChannel(roomId); } - } } long parentId = object.getParentId(); diff --git a/src/services/DevService.java b/src/services/DevService.java index fd669c4b..452b7321 100644 --- a/src/services/DevService.java +++ b/src/services/DevService.java @@ -92,8 +92,7 @@ public class DevService implements INetworkDispatch { suiOptions.put((long) 120, "House Deeds"); suiOptions.put((long) 125, "Crafting Tools"); suiOptions.put((long) 130, "Vehicle Deeds"); - suiOptions.put((long) 121, "Sandbox City"); - suiOptions.put((long) 140, "Guild Registry Device (PDA)"); + suiOptions.put((long) 121, "Sandbox City"); } break; @@ -108,6 +107,7 @@ public class DevService implements INetworkDispatch { suiOptions.put((long) 41, "Tusken Rucksack"); suiOptions.put((long) 42, "Heroism Jewlery Set"); suiOptions.put((long) 43, "Breath of Heaven"); + suiOptions.put((long) 140, "Guild Registry Device (PDA)"); break; case 5: // [Items] Armor suiOptions.put((long) 50, "Assault Armor"); diff --git a/src/services/GuildService.java b/src/services/GuildService.java index c59b1580..4d7dd88a 100644 --- a/src/services/GuildService.java +++ b/src/services/GuildService.java @@ -26,6 +26,8 @@ import java.util.HashMap; import java.util.Map; import java.util.Vector; +import protocol.swg.chat.ChatOnSendRoomMessage; +import protocol.swg.chat.ChatRoomMessage; import resources.common.OutOfBand; import resources.datatables.DisplayType; import resources.guild.Guild; @@ -70,7 +72,7 @@ public class GuildService implements INetworkDispatch { } - public Guild createGuild(String abbreviation, String name, SWGObject leader) { + public Guild createGuild(String abbreviation, String name, CreatureObject leader) { if (leader == null) return null; @@ -83,6 +85,9 @@ public class GuildService implements INetworkDispatch { guild.setChatRoomId(guildChat.getRoomId()); object.getGuildList().add(guild); + + GuildMember member = joinGuild(guild, leader, null); + member.giveAllPermissions(); return guild; } @@ -142,6 +147,44 @@ public class GuildService implements INetworkDispatch { return member; } + public void handleCreateGuildName(CreatureObject actor, SWGObject creationSource) { + if (actor.getGuildId() != 0) { actor.sendSystemMessage("@guild:create_fail_in_guild", DisplayType.Broadcast); return; } + + SUIWindow window = core.suiService.createInputBox(InputBoxType.INPUT_BOX_OK_CANCEL, "@guild:create_name_title", "@guild:create_name_prompt", actor, null, 0, + (owner, eventType, returnList) -> { + String guildName = returnList.get(0); // TODO: Character checks + + if (guildName.length() > 24) { actor.sendSystemMessage("@guild:create_fail_name_bad_length", DisplayType.Broadcast); handleCreateGuildName(actor, creationSource); return;} + if (getGuildByName(guildName) != null) { actor.sendSystemMessage("@guild:create_fail_name_in_use", DisplayType.Broadcast); handleCreateGuildName(actor, creationSource); return;} + + handleCreateGuildAbbrev(actor, guildName, creationSource); + }); + window.setProperty("txtInput:MaxLength", "24"); + window.setProperty("txtInput:NumericInteger", "False"); + + core.suiService.openSUIWindow(window); + } + + public void handleCreateGuildAbbrev(CreatureObject actor, String guildName, SWGObject creationSource) { + SUIWindow window = core.suiService.createInputBox(InputBoxType.INPUT_BOX_OK_CANCEL, "@guild:create_abbrev_title", "@guild:create_abbrev_prompt", actor, null, 0, + (owner, eventType, returnList) -> { + String abbrev = returnList.get(0); // TODO: Character checks + + if (abbrev.length() > 5) { actor.sendSystemMessage("@guild:create_fail_abbrev_bad_length", DisplayType.Broadcast); handleCreateGuildAbbrev(actor, guildName, creationSource); return;} + if (getGuildByAbbreviation(abbrev) != null) { actor.sendSystemMessage("@guild:create_fail_abbrev_in_use", DisplayType.Broadcast); handleCreateGuildAbbrev(actor, guildName, creationSource); return;} + + Guild guild = createGuild(abbrev, guildName, actor); + if (guild != null && creationSource != null && creationSource.getTemplate().equals("object/tangible/furniture/technical/shared_guild_registry_initial.iff")) { + core.objectService.destroyObject(creationSource); + } + }); + + window.setProperty("txtInput:MaxLength", "4"); + window.setProperty("txtInput:NumericInteger", "False"); + + core.suiService.openSUIWindow(window); + } + public void handleViewPermissionsList(CreatureObject actor, Guild guild) { final SUIWindow window = core.suiService.createSUIWindow("Script.tablePage", actor, null, (float) 0); window.setProperty("bg.caption.lblTitle:Text", "Permissions List"); @@ -194,8 +237,9 @@ public class GuildService implements INetworkDispatch { }); core.suiService.openSUIWindow(window); } - public void handleChangeMemberPermissions(CreatureObject actor, Guild guild, GuildMember target) { handleChangeMemberPermissions(actor, guild, target, ""); - } + + public void handleChangeMemberPermissions(CreatureObject actor, Guild guild, GuildMember target) { handleChangeMemberPermissions(actor, guild, target, ""); } + public void handleChangeMemberPermissions(CreatureObject actor, Guild guild, GuildMember target, String source) { GuildMember requester = guild.getMember(actor.getObjectID()); @@ -210,17 +254,17 @@ public class GuildService implements INetworkDispatch { Vector returnList = new Vector(); returnList.add("List.lstList:SelectedRow"); - if (!source.isEmpty() || !source.equals("")) { + /*if (!source.isEmpty() || !source.equals("")) { window.setProperty("btnOther:Visible", "True"); window.setProperty("btnOther:Text", "Back"); - window.addHandler(1, "", Trigger.TRIGGER_UPDATE, returnList, (owner, eventType, resultList) -> { + window.addHandler(1, "btnOther", Trigger.TRIGGER_OK, returnList, (owner, eventType, resultList) -> { switch(source) { case "PermissionsList": handleViewPermissionsList(actor, guild); break; } }); - } + }*/ window.addHandler(0, "", Trigger.TRIGGER_OK, returnList, (owner, eventType, resultList) -> { if (resultList.size() == 0) return; @@ -282,7 +326,92 @@ public class GuildService implements INetworkDispatch { core.suiService.openSUIWindow(window); } - public void handleGuildSponsor(CreatureObject actor) { + public void handleChangeGuildMotd(CreatureObject actor, Guild guild) { + SUIWindow window = core.suiService.createInputBox(InputBoxType.INPUT_BOX_OK_CANCEL, "@guild:menu_member_motd", "@guild:prompt_member_motd_message", actor, null, 0, + (owner, eventType, resultList) -> { + String newMotd = resultList.get(0); + + guild.setMotd(newMotd); + + actor.sendSystemMessage("Guild Message of the Day set to \"" + newMotd + "\".", DisplayType.Broadcast); + }); + + window.setProperty("inputBox:Size", "506,430"); + core.suiService.openSUIWindow(window); + } + + public void handleViewGuildMembers(CreatureObject actor, Guild guild) { + final SUIWindow window = core.suiService.createSUIWindow("Script.tablePage", actor, null, (float) 0); + window.setProperty("bg.caption.lblTitle:Text", "@guild:members_title"); + window.setProperty("comp.Prompt.lblPrompt:Text", "@guild:members_prompt"); + //if (actingMember.getAllPermissions(actingMember).size() > 2) window.setProperty("comp.Prompt.lblPrompt:Text", "@guild:members_show_prompt"); + window.setProperty("tablePage:Size", "785,634"); + // window.setProperty("comp.TablePage.table:columsizedatasource", "dsColSizes"); + window.setProperty("comp.TablePage.header:ScrollExtent", "444,30"); + window.addTableColumn("@guild:table_title_level", "text"); + window.addTableColumn("@guild:table_title_name", "text"); + window.addTableColumn("@guild:table_title_profession", "text"); + window.addTableColumn("@guild:table_title_rank", "text"); + window.addTableColumn("@guild:table_title_status", "text"); + window.addTableColumn("@guild:table_title_title", "text"); + window.addTableColumn("@guild:table_title_war_excluded", "text"); + window.addTableColumn("@guild:table_title_war_included", "text"); + + Map members = guild.getMembers(); + members.entrySet().forEach(e -> { + GuildMember member = e.getValue(); + for (SUITableItem column : window.getTableItems()) { + switch(column.getItemName()) { + case "@guild:table_title_level": + window.addTableCell(String.valueOf(member.getLevel()), e.getKey(), column.getIndex()); + continue; + case "@guild:table_title_name": + window.addTableCell(member.getName(), e.getKey(), column.getIndex()); + continue; + case "@guild:table_title_profession": + window.addTableCell(member.getProfession(), e.getKey(), column.getIndex()); + continue; + case "@guild:table_title_rank": + window.addTableCell(member.getRank(), e.getKey(), column.getIndex()); + continue; + case "@guild:table_title_status": + //window.addTableCell(member.getStatus(), e.getKey(), column.getIndex()); + continue; + case "@guild:table_title_war_excluded": + if (member.isWarExcluded()) window.addTableCell("X", e.getKey(), column.getIndex()); + else window.addTableCell("", e.getKey(), column.getIndex()); + continue; + case "@guild:table_title_war_included": + if (member.isWarExclusive()) window.addTableCell("X", e.getKey(), column.getIndex()); + else window.addTableCell("", e.getKey(), column.getIndex()); + continue; + } + } + }); + + Vector returnList = new Vector(); + returnList.add("comp.TablePage.table:SelectedRow"); + + window.addHandler(0, "", Trigger.TRIGGER_OK, returnList, (owner, eventType, resultList) -> { + + long objectId = window.getTableObjIdByRow(Integer.parseInt(resultList.get(0))); + + if (objectId == 0) + return; + + GuildMember selectedMember = guild.getMember(objectId); + + if (selectedMember == null) + return; + + //handleMemberOptions((CreatureObject) owner, guild, selectedMember); + }); + + core.suiService.openSUIWindow(window); + } + + + public void handleGuildSponsorWindow(CreatureObject actor) { SUIWindow wndSponsorPlayer = core.suiService.createInputBox(InputBoxType.INPUT_BOX_OK_CANCEL, "@guild:sponsor_title", "@guild:sponsor_prompt", actor, null, (float) 10, (sponsor, eventType, returnList) -> { if (eventType != 0) @@ -322,17 +451,51 @@ public class GuildService implements INetworkDispatch { guild.getSponsoredPlayers().put(cOwner.getObjectID(), cOwner.getCustomName()); - actor.sendSystemMessage(OutOfBand.ProsePackage("@guild:sponsor_self", "TU", cOwner.getCustomName(), "TT", guild.getName()), DisplayType.Broadcast); ((CreatureObject)cOwner).sendSystemMessage(OutOfBand.ProsePackage("@guild:sponsor_target", "TT", guild.getName(), "TU", actor.getCustomName()), DisplayType.Broadcast); guild.sendGuildMail(guild.getName(), "@guildmail:sponsor_subject", new Stf("@guildmail:sponsor_text").getStfValue().replace("%TU", actor.getCustomName()).replace("%TT", cOwner.getCustomName())); }); core.suiService.openSUIWindow(wndSponsoredConfirm); + + actor.sendSystemMessage(OutOfBand.ProsePackage("@guild:sponsor_self", "TU", pSponsored.getCustomName(), "TT", invitingGuild.getName()), DisplayType.Broadcast); }); core.suiService.openSUIWindow(wndSponsorPlayer); } + + public void handleGuildDisband(CreatureObject actor, Guild guild) { + + Map members = guild.getMembers(); + + members.entrySet().forEach(e -> { + CreatureObject target = core.objectService.getCreatureFromDB(e.getKey()); + + if (target != null) { + + target.setGuildId(0); + + // Update association device + TangibleObject datapad = (TangibleObject) target.getSlottedObject("datapad"); + + if (datapad != null) { + datapad.viewChildren(target, true, false, (obj) -> { + if (obj instanceof IntangibleObject && obj.getTemplate().equals("object/intangible/data_item/shared_guild_stone.iff")) { + obj.setStringAttribute("guild_name", null); + obj.setStringAttribute("guild_abbrev", null); + obj.setStringAttribute("guild_leader", null); + } + }); + } + } + }); + + guild.sendGuildMail(guild.getName(), "@guildmail:disband_subject", new Stf("@guildmail:disband_text").getStfValue().replace("%TU", actor.getCustomName())); + + removeGuild(guild.getId()); + } + + public void handleManageSponsoredPlayers(CreatureObject actor) { Guild guild = getGuildById(actor.getGuildId()); @@ -426,6 +589,89 @@ public class GuildService implements INetworkDispatch { core.chatService.sendPersistentMessageHeader(sponsoree.getClient(), declinedMail); } + + public void showKickConfirmWindow(CreatureObject actor, CreatureObject target, Guild guild) { + + if (target.getObjectID() == guild.getLeader() && target.getObjectID() == actor.getObjectID()) { + actor.sendSystemMessage("@guild:leave_fail_leader_tried_to_leave", DisplayType.Broadcast); + return; + } else if (target.getObjectID() == guild.getLeader()) { + actor.sendSystemMessage("@guild:guild_no_permission_operation", DisplayType.Broadcast); + return; + } + + SUIWindow kickPrompt = core.suiService.createMessageBox(MessageBoxType.MESSAGE_BOX_YES_NO, "@guild:kick_title", + new Stf("@guild:kick_prompt").getStfValue().replace("%TU", target.getCustomName()), actor, null, 0); + + kickPrompt.addHandler(0, "", Trigger.TRIGGER_OK, new Vector(), (owner, eventType, resultList) -> { + leaveGuild(actor, target, guild); + }); + + core.suiService.openSUIWindow(kickPrompt); + } + + public void showDisbandConfirmWindow(CreatureObject actor, Guild guild) { + + if (!guild.getMember(actor.getObjectID()).hasDisbandPermission() && actor.getObjectID() != guild.getLeader()) { + actor.sendSystemMessage("@guild:guild_no_permission_operation", DisplayType.Broadcast); + return; + } + + SUIWindow disbandConfirm = core.suiService.createMessageBox(MessageBoxType.MESSAGE_BOX_YES_NO, "@guild:disband_title", "@guild:disband_prompt", actor, null, 0); + disbandConfirm.addHandler(0, "", Trigger.TRIGGER_OK, new Vector(), (owner, eventType, resultList) -> { + handleGuildDisband(actor, guild); + }); + core.suiService.openSUIWindow(disbandConfirm); + } + + + public void leaveGuild(CreatureObject actor, CreatureObject target, Guild guild) { + GuildMember actingMember = guild.getMember(actor.getObjectID()); + + if (actingMember == null) + return; + + if ((!actingMember.hasKickPermission() && actor != target) || (target.getObjectID() == guild.getLeader() && target.getObjectID() != actor.getObjectID())) { + actor.sendSystemMessage("@guild:guild_no_permission_operation", DisplayType.Broadcast); + return; + } + + if (actor.getObjectID() != target.getObjectID()) { + + guild.sendGuildMail(guild.getName(), "@guildmail:kick_subject", new Stf("@guildmail:kick_text").getStfValue().replace("%TU", actor.getCustomName()).replace("%TT", target.getCustomName())); + + actor.sendSystemMessage(OutOfBand.ProsePackage("@guild:kick_self", "TU", target.getCustomName(), "TT", guild.getName()), DisplayType.Broadcast); + + if (target.isInQuadtree()) + target.sendSystemMessage(OutOfBand.ProsePackage("@guild:kick_target", "TU", actor.getCustomName(), "TT", guild.getName()), DisplayType.Broadcast); + + } else { + if (target.getObjectID() == guild.getLeader()) { + actor.sendSystemMessage("@guild:leave_fail_leader_tried_to_leave", DisplayType.Broadcast); + return; + } else { + guild.sendGuildMail(guild.getName(), "@guildmail:leave_subject", new Stf("@guildmail:leave_text").getStfValue().replace("%TU", actor.getCustomName())); + actor.sendSystemMessage(OutOfBand.ProsePackage("@guild:leave_self", "TU", guild.getName()), DisplayType.Broadcast); + } + } + guild.getMembers().remove(target.getObjectID()); + target.setGuildId(0); + core.chatService.leaveChatRoom(target, guild.getChatRoomId()); + // Update association device + TangibleObject datapad = (TangibleObject) target.getSlottedObject("datapad"); + + if (datapad != null) { + datapad.viewChildren(target, true, false, (obj) -> { + if (obj instanceof IntangibleObject && obj.getTemplate().equals("object/intangible/data_item/shared_guild_stone.iff")) { + obj.setStringAttribute("guild_name", null); + obj.setStringAttribute("guild_abbrev", null); + obj.setStringAttribute("guild_leader", null); + } + }); + } + } + + public void sendMailToGuild(String sender, String subject, String message, int guildId) { Guild guild = getGuildById(guildId); @@ -435,24 +681,53 @@ public class GuildService implements INetworkDispatch { guild.sendGuildMail(sender, subject, message); } + public void sendGuildMotd(CreatureObject target, Guild guild) { + if (guild == null || guild.getMotd().isEmpty()) + return; + + ChatRoom room = core.chatService.getChatRoom(guild.getChatRoomId()); + + if (room == null) + return; + + ChatRoomMessage roomMessage = new ChatRoomMessage(guild.getChatRoomId(), "Message of the Day", guild.getMotd()); + target.getClient().getSession().write(roomMessage.serialize()); + } + + public GuildObject getGuildObject() { return object; } + public SWGSet getGuildList() { return object.getGuildList(); } public Guild getGuildById(int id) { - return object.getGuildList().stream().filter(g -> g.getId() == id).findFirst().get(); - } - - public Guild getGuildByAbbreviation(String abbreviation) { - return object.getGuildList().stream().filter(g -> g.getAbbreviation().equals(abbreviation)).findFirst().get(); + for (Guild guild : object.getGuildList()) { + if (guild.getId() == id) + return guild; + } + return null; } + + public Guild getGuildByAbbreviation(String abbreviation) { + for (Guild guild : object.getGuildList()) { + if (guild.getAbbreviation().equals(abbreviation)) + return guild; + } + return null; + } + + public Guild getGuildByName(String name) { - return object.getGuildList().stream().filter(g -> g.getName().equals(name)).findFirst().get(); + for (Guild guild : object.getGuildList()) { + if (guild.getName().equals(name)) + return guild; + } + return null; } public boolean removeGuild(int id) { @@ -465,17 +740,6 @@ public class GuildService implements INetworkDispatch { return false; } - - public boolean removeGuild(String abbreviation) { - Guild guild = getGuildByAbbreviation(abbreviation); - - if (guild != null) { - object.getGuildList().remove(guild); - return true; - } - - return false; - } @Override public void insertOpcodes(Map swgOpcodes, Map objControllerOpcodes) { diff --git a/src/services/PlayerService.java b/src/services/PlayerService.java index 0e839581..9eb592f6 100644 --- a/src/services/PlayerService.java +++ b/src/services/PlayerService.java @@ -621,6 +621,14 @@ public class PlayerService implements INetworkDispatch { grantLevel(creature, level); player.setProfessionIcon(Professions.get(profession)); + + if (creature.getGuildId() != 0) { + Guild guild = core.guildService.getGuildById(creature.getGuildId()); + + if (guild != null && guild.getMembers().containsKey(creature.getObjectID())) { + guild.getMember(creature.getObjectID()).setProfession(getFormalProfessionName(profession)); + } + } } /* @@ -709,6 +717,14 @@ public class PlayerService implements INetworkDispatch { creature.setGrantedHealth(0); creature.setLevel((short) 1); + + if (creature.getGuildId() != 0) { + Guild guild = core.guildService.getGuildById(creature.getGuildId()); + + if (guild != null && guild.getMembers().containsKey(creature.getObjectID())) { + guild.getMember(creature.getObjectID()).setLevel((short) 1); + } + } } /* @@ -879,6 +895,14 @@ public class PlayerService implements INetworkDispatch { creature.showFlyText(OutOfBand.ProsePackage("@cbt_spam:skill_up"), 2.5f, new RGB(154, 205, 50), 0, true); creature.playEffectObject("clienteffect/skill_granted.cef", ""); creature.playMusic("sound/music_acq_bountyhunter.snd"); + + if (creature.getGuildId() != 0) { + Guild guild = core.guildService.getGuildById(creature.getGuildId()); + + if (guild != null && guild.getMembers().containsKey(creature.getObjectID())) { + guild.getMember(creature.getObjectID()).setLevel((short) level); + } + } } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } diff --git a/src/services/SimulationService.java b/src/services/SimulationService.java index bff3bb41..fd824cc7 100644 --- a/src/services/SimulationService.java +++ b/src/services/SimulationService.java @@ -811,6 +811,13 @@ public class SimulationService implements INetworkDispatch { core.mountService.storeAll(object); + for (Integer roomId : ghost.getJoinedChatChannels()) { + ChatRoom room = core.chatService.getChatRoom(roomId.intValue()); + + if (room != null) { core.chatService.leaveChatRoom(object, roomId.intValue()); } + // work-around for any channels that may have been deleted, or only spawn on server startup, that were added to the joined channels + else { ghost.removeChannel(roomId); } + } /* object.createTransaction(core.getCreatureODB().getEnvironment()); core.getCreatureODB().put(object, Long.class, CreatureObject.class, object.getTransaction()); diff --git a/src/services/chat/ChatService.java b/src/services/chat/ChatService.java index a37eed1b..202e2601 100644 --- a/src/services/chat/ChatService.java +++ b/src/services/chat/ChatService.java @@ -48,6 +48,7 @@ import engine.resources.service.INetworkDispatch; import engine.resources.service.INetworkRemoteEvent; import resources.common.*; import resources.datatables.DisplayType; +import resources.guild.Guild; import resources.objects.creature.CreatureObject; import resources.objects.player.PlayerObject; import protocol.swg.AddIgnoreMessage; @@ -262,9 +263,31 @@ public class ChatService implements INetworkDispatch { if(sender == null) return; - // TODO: Recipient handling for values: citizens, group, guild, guild ranks (ace, boot, admiral, etc.) - Nulls at this point atm - SWGObject recipient = getObjectByFirstName(packet.getRecipient()); + // TODO: Recipient handling for values: citizens, group, guild ranks (ace, boot, admiral, etc.) + if (packet.getRecipient().equals("guild")) { + Guild guild = core.guildService.getGuildById(((CreatureObject) sender).getGuildId()); + if (guild == null || !guild.getMembers().containsKey(sender.getObjectID())) { + ChatOnSendPersistentMessage response = new ChatOnSendPersistentMessage(4, packet.getCounter()); + session.write(response.serialize()); + return; + } + + if (!guild.getMember(sender.getObjectID()).hasMailPermission()) { + ((CreatureObject) sender).sendSystemMessage("@guild:generic_fail_no_permission", (byte) 0); + ChatOnSendPersistentMessage response = new ChatOnSendPersistentMessage(4, packet.getCounter()); + session.write(response.serialize()); + return; + } + guild.sendGuildMail(sender.getCustomName(), packet.getSubject(), packet.getMessage()); + + ChatOnSendPersistentMessage response = new ChatOnSendPersistentMessage(0, packet.getCounter()); + session.write(response.serialize()); + return; + } + + SWGObject recipient = getObjectByFirstName(packet.getRecipient()); + PlayerObject recipientGhost = (PlayerObject) recipient.getSlottedObject("ghost"); if (recipientGhost.getIgnoreList().contains(sender.getCustomName().toLowerCase())) @@ -941,7 +964,9 @@ public class ChatService implements INetworkDispatch { } room.addUser(user.toLowerCase()); - ((CreatureObject) player).getPlayerObject().addChannel(roomId); + if (!((CreatureObject) player).getPlayerObject().isMemberOfChannel(roomId)) { + ((CreatureObject) player).getPlayerObject().addChannel(roomId); + } return true; } return false; @@ -975,7 +1000,7 @@ public class ChatService implements INetworkDispatch { } }); - ((PlayerObject) player.getSlottedObject("ghost")).removeChannel(roomId); + ((PlayerObject) player.getSlottedObject("ghost")).removeChannel((Integer) roomId); } public void sendChatRoomMessage(CreatureObject sender, int roomId, int msgId, String message) { diff --git a/src/services/object/ObjectService.java b/src/services/object/ObjectService.java index 5fecc24d..1e21f27c 100644 --- a/src/services/object/ObjectService.java +++ b/src/services/object/ObjectService.java @@ -46,8 +46,10 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import resources.common.*; +import resources.datatables.DisplayType; import resources.datatables.Options; import resources.datatables.PlayerFlags; +import resources.guild.Guild; import resources.harvest.SurveyTool; import org.apache.mina.core.buffer.IoBuffer; @@ -902,8 +904,15 @@ public class ObjectService implements INetworkDispatch { } } - if(!core.getConfig().getString("MOTD").equals("")) - creature.sendSystemMessage(core.getConfig().getString("MOTD"), (byte) 2); + creature.sendSystemMessage(core.getMotd(), DisplayType.Chat); + + if (creature.getGuildId() != 0) { + Guild guild = core.guildService.getGuildById(creature.getGuildId()); + + if (guild != null && guild.getMembers().containsKey(creature.getObjectID())) { + core.guildService.sendGuildMotd(creature, guild); + } + } if (core.getBountiesODB().contains(creature.getObjectID())) core.missionService.getBountyMap().put(creature.getObjectID(), (BountyListItem) core.getBountiesODB().get(creature.getObjectID()));