diff --git a/src/main/java/com/l2jserver/Test.java b/src/main/java/com/l2jserver/Test.java new file mode 100644 index 000000000..29757a69a --- /dev/null +++ b/src/main/java/com/l2jserver/Test.java @@ -0,0 +1,41 @@ +/* + * This file is part of l2jserver . + * + * l2jserver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * l2jserver 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with l2jserver. If not, see . + */ +package com.l2jserver; + +import com.l2jserver.util.html.markup.HtmlTemplate; +import com.l2jserver.util.html.markup.MarkupTag; + +/** + * @author Rogiel + */ +public class Test { + /** + * @param args + */ + public static void main(String[] args) { + final HtmlTemplate template = new HtmlTemplate("Notice") { + @Override + public void build(MarkupTag body) { + body.text("This NPC is not yet implemented!").br(); + body.text("This NPC is not yet implemented!", "000000").br(); + body.text("This NPC is not yet implemented!", "ffffff").p(); + body.addLink("Click me!", "test"); + } + }; + System.out.println(template.toHtmlString()); + } +} diff --git a/src/main/java/com/l2jserver/game/net/packet/server/CharacterInformationPacket.java b/src/main/java/com/l2jserver/game/net/packet/server/CharacterInformationPacket.java index d2da9d2ca..657a228a4 100644 --- a/src/main/java/com/l2jserver/game/net/packet/server/CharacterInformationPacket.java +++ b/src/main/java/com/l2jserver/game/net/packet/server/CharacterInformationPacket.java @@ -278,7 +278,7 @@ public class CharacterInformationPacket extends AbstractServerPacket { buffer.writeShort(500); // inventory limit buffer.writeInt(character.getCharacterClass().id); - buffer.writeInt(0x01); // special effects? circles around player... + buffer.writeInt(0x00); // special effects? circles around player... buffer.writeInt(200); // max cp buffer.writeInt(200); // cur cp buffer.writeByte(0x00); // is mount or is airshilhelp = 0; otherwise diff --git a/src/main/java/com/l2jserver/service/game/CharacterServiceImpl.java b/src/main/java/com/l2jserver/service/game/CharacterServiceImpl.java index d17f3c699..5dbe42524 100644 --- a/src/main/java/com/l2jserver/service/game/CharacterServiceImpl.java +++ b/src/main/java/com/l2jserver/service/game/CharacterServiceImpl.java @@ -30,6 +30,7 @@ import com.l2jserver.game.net.packet.server.CharacterTargetSelectedPacket; import com.l2jserver.game.net.packet.server.GameGuardQueryPacket; import com.l2jserver.game.net.packet.server.NPCInformationPacket; import com.l2jserver.model.id.object.CharacterID; +import com.l2jserver.model.template.NPCTemplate; import com.l2jserver.model.world.L2Character; import com.l2jserver.model.world.L2Character.CharacterMoveType; import com.l2jserver.model.world.NPC; @@ -119,9 +120,10 @@ public class CharacterServiceImpl extends AbstractService implements if (conn == null) return; if (!worldService.add(character)) + // TODO this should throw an exception // character is already in the world! return; - + itemDao.loadInventory(character); // chat listener @@ -146,6 +148,8 @@ public class CharacterServiceImpl extends AbstractService implements // this listener will be filtered so that only interesting events are // dispatched, once a event arrives will be possible to check check if // the given event will be broadcasted or not + // TODO this should not be here, it should be i world service or a newly + // created broadcast service. final WorldListener broadcastListener = new FilteredWorldListener( new KnownListFilter(character)) { @Override @@ -206,7 +210,8 @@ public class CharacterServiceImpl extends AbstractService implements run(character); // broadcast knownlist -- trashy implementation - // TODO should be moved to world service + // TODO should be moved to world service or a newly created broadcast + // service, whichever fits the purpose for (final WorldObject o : worldService.iterable(new KnownListFilter( character))) { if (o instanceof NPC) { @@ -226,21 +231,22 @@ public class CharacterServiceImpl extends AbstractService implements public void move(L2Character character, Coordinate coordinate) { final CharacterID id = character.getID(); final Lineage2Connection conn = networkService.discover(id); - // for now, let's just write the packet - // aiService.walk(character, coordinate); + // we don't set the character coordinate here, this will be done by + // validation packets, sent by client - final Coordinate source = character.getPosition(); - // we don't set the character coordinate yet, this will be done by - // validate coordinate + // for now, let's just write the packet, we don't have much validation + // to be done yet. With character validation packet, another packet of + // these will be broadcasted. conn.write(new ActorMovementPacket(character, coordinate)); // we don't dispatch events here, they will be dispatched by - // receivedValidation at fixed time intervals. + // with the same packet referred up here. } @Override public void leaveWorld(L2Character character) { if (!worldService.remove(character)) return; + spawnService.unspawn(character); eventDispatcher.dispatch(new CharacterLeaveWorldEvent(character)); } @@ -250,21 +256,33 @@ public class CharacterServiceImpl extends AbstractService implements final Lineage2Connection conn = networkService.discover(id); if (target == null && character.getTargetID() != null) { + // if is trying to select null (remove target) and the character has + // an target, trigger an deselect final Actor oldTarget = character.getTarget(); character.setTargetID(null); eventDispatcher.dispatch(new CharacterTargetDeselectedEvent( character, oldTarget)); + // TODO we need to send an packet here to inform of deselection } else if (target != null && !target.getID().equals(character.getID())) { + // if new target is not null and the current character target is + // null or different, trigger the selection. if (character.getTargetID() != null) { + // first deselect old target eventDispatcher.dispatch(new CharacterTargetDeselectedEvent( character, character.getTarget())); } - character.setTargetID(null); + // now select the new target + character.setTargetID(target.getID()); eventDispatcher.dispatch(new CharacterTargetSelectedEvent( character, target)); conn.write(new CharacterTargetSelectedPacket(target)); } else { + // this indicates an inconsistency, send an action failed and reset + // target, i.e. deselect with no target + // TODO instead of sending action failed, we should throw an + // exception here conn.sendActionFailed(); + character.setTargetID(null); } } @@ -275,11 +293,15 @@ public class CharacterServiceImpl extends AbstractService implements // check if this Actor can be attacked if (target instanceof NPC) { final NPC npc = (NPC) target; - if (!npc.getTemplate().isAttackable()) { + final NPCTemplate template = npc.getTemplate(); + if (!template.isAttackable()) { conn.write(ActionFailedPacket.SHARED_INSTANCE); return; } + // first try to target this, if it is not already + target(character, target); + // TODO issue attack } } @@ -298,19 +320,27 @@ public class CharacterServiceImpl extends AbstractService implements public void walk(L2Character character) { final CharacterID id = character.getID(); final Lineage2Connection conn = networkService.discover(id); + // test if character is running if (character.getMoveType() == CharacterMoveType.RUN) { + // if running set mode to walk and broadcast packet character.setMoveType(CharacterMoveType.WALK); conn.broadcast(new CharacterMovementTypePacket(character)); + // TODO dispatch move change type event } + // TODO we need to throw an exception if character is not running } @Override public void run(L2Character character) { final CharacterID id = character.getID(); final Lineage2Connection conn = networkService.discover(id); + // test if character is walking if (character.getMoveType() == CharacterMoveType.WALK) { + // if running walking mode to run and broadcast packet character.setMoveType(CharacterMoveType.RUN); conn.broadcast(new CharacterMovementTypePacket(character)); + // TODO dispatch move change type event } + // TODO we need to throw an exception if character is not walking } } diff --git a/src/main/java/com/l2jserver/service/game/SpawnServiceImpl.java b/src/main/java/com/l2jserver/service/game/SpawnServiceImpl.java index 048f1a1de..87a2da15a 100644 --- a/src/main/java/com/l2jserver/service/game/SpawnServiceImpl.java +++ b/src/main/java/com/l2jserver/service/game/SpawnServiceImpl.java @@ -79,6 +79,7 @@ public class SpawnServiceImpl extends AbstractService implements SpawnService { point = spawnable.getPoint(); if (point == null) { // not point send and no point stored, aborting + // TODO this should throw an exception log.warn("Trying to spawn {} to a null point", spawnable); return; } @@ -87,6 +88,7 @@ public class SpawnServiceImpl extends AbstractService implements SpawnService { spawnable.setPoint(point); // register object in the world if (!worldService.add(spawnable)) + // TODO this should throw an exception // object was already in world return; @@ -99,11 +101,11 @@ public class SpawnServiceImpl extends AbstractService implements SpawnService { event = null; } + // TODO throw an exception if event is null if (event != null) // dispatch spawn event eventDispatcher.dispatch(event); - - // TODO broadcast this object to players nearby + // remember: broadcasting is done through events! } @Override @@ -113,13 +115,14 @@ public class SpawnServiceImpl extends AbstractService implements SpawnService { final Lineage2Connection conn = networkService .discover((CharacterID) player.getID()); if (conn == null) + // TODO throw an exception here return; conn.write(new CharacterTeleportPacket(conn.getCharacter())); } // dispatch teleport event eventDispatcher.dispatch(new PlayerTeleportEvent(player, coordinate .toPoint())); - // TODO broadcast this player new position + // remember: broadcasting is done through events! } @Override diff --git a/src/main/java/com/l2jserver/service/game/ai/AIServiceImpl.java b/src/main/java/com/l2jserver/service/game/ai/AIServiceImpl.java index bde96de27..f48ff322c 100644 --- a/src/main/java/com/l2jserver/service/game/ai/AIServiceImpl.java +++ b/src/main/java/com/l2jserver/service/game/ai/AIServiceImpl.java @@ -22,7 +22,6 @@ import com.l2jserver.service.AbstractService; import com.l2jserver.service.AbstractService.Depends; import com.l2jserver.service.ServiceStartException; import com.l2jserver.service.ServiceStopException; -import com.l2jserver.service.game.CharacterService; import com.l2jserver.service.game.template.TemplateService; import com.l2jserver.service.game.world.WorldService; import com.l2jserver.service.game.world.event.WorldEventDispatcher; @@ -31,7 +30,7 @@ import com.l2jserver.service.threading.ThreadService; import com.l2jserver.util.dimensional.Coordinate; /** - * Default implementation for {@link CharacterService}. + * Default implementation for {@link AIService}. * * @author Rogiel */ diff --git a/src/main/java/com/l2jserver/service/game/world/WorldServiceImpl.java b/src/main/java/com/l2jserver/service/game/world/WorldServiceImpl.java index 22937d334..dce14a452 100644 --- a/src/main/java/com/l2jserver/service/game/world/WorldServiceImpl.java +++ b/src/main/java/com/l2jserver/service/game/world/WorldServiceImpl.java @@ -111,6 +111,7 @@ public class WorldServiceImpl extends AbstractService implements WorldService { if (filter.accept(object)) return (T) object; } + // TODO throw exception if object is not found return null; } diff --git a/src/main/resources/sql/actor_skill.sql b/src/main/resources/sql/actor_skill.sql new file mode 100644 index 000000000..1109f650c --- /dev/null +++ b/src/main/resources/sql/actor_skill.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS `actor_skill` ( + `actor_id` int(10) NOT NULL, + `skill_id` int(10) NOT NULL, + `level` int(2) NOT NULL DEFAULT '1', + PRIMARY KEY (`actor_id`,`skill_id`), + KEY `actor_id` (`actor_id`), + KEY `skill_id` (`skill_id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; \ No newline at end of file diff --git a/src/main/resources/sql/character.sql b/src/main/resources/sql/character.sql index 5138dc787..09122b06a 100644 --- a/src/main/resources/sql/character.sql +++ b/src/main/resources/sql/character.sql @@ -1,9 +1,9 @@ -CREATE TABLE `character` ( +CREATE TABLE IF NOT EXISTS `character` ( `character_id` int(12) NOT NULL, `account_id` varchar(50) NOT NULL, - `clan_id` int(10) NOT NULL, + `clan_id` int(10) DEFAULT NULL, `name` varchar(50) NOT NULL, - `race` enum('HUMAN', 'ELF', 'DARK_ELF', 'ORC', 'DWARF', 'KAMAEL') NOT NULL, + `race` enum('HUMAN','ELF','DARK_ELF','ORC','DWARF','KAMAEL') NOT NULL, `class` enum('HUMAN_FIGHTER','WARRIOR','GLADIATOR','WARLORD','KNIGHT','PALADIN','DARK_AVENGER','ROGUE','TREASURE_HUNTER','HAWKEYE','DUELIST','DREADNOUGHT','phoenixKnight','hellKnight','sagittarius','adventurer','HUMAN_MYSTIC','WIZARD','SORCEROR','NECROMANCER','WARLOCK','CLERIC','BISHOP','PROPHET','ARCHMAGE','SOULTAKER','ARCANA_LORD','CARDINAL','HIEROPHANT','ELVEN_FIGHTER','ELVEN_KNIGHT','TEMPLE_KNIGHT','SWORD_SINGER','ELVEN_SCOUT','PLAINS_WALKER','SILVER_RANGER','EVA_TEMPLAR','SWORD_MUSE','WIND_RIDER','MOONLIGHT_SENTINEL','ELVEN_MYSTIC','ELVEN_WIZARD','SPELLSINGER','ELEMENTAL_SUMMONER','ORACLE','ELDER','MYSTIC_MUSE','ELEMENTAL_MASTER','EVA_SAINT','DARK_FIGHTER','PALUS_KNIGHT','SHILLIEN_KNIGHT','BLADEDANCER','ASSASSIN','ABYSS_WALKER','PHANTOM_RANGER','SHILLIEN_TEMPLAR','spectralDancer','ghostHunter','ghostSentinel','DARK_MYSTIC','DARK_WIZARD','SPELLHOWLER','PHANTOM_SUMMONER','SHILLIEN_ORACLE','SHILLIEN_ELDER','STORM_SCREAMER','SPECTRAL_MASTER','SHILLIEAN_SAINT','ORC_FIGHTER','ORC_RAIDER','DESTROYER','ORC_MONK','TYRANT','TITAN','GRAND_KHAUATARI','ORC_MYSTIC','ORC_SHAMAN','OVERLORD','WARCRYER','DOMINATOR','DOOMCRYER','DWARVEN_FIGHTER','SCAVENGER','BOUNTY_HUNTER','ARTISAN','WARSMITH','FORTUNE_SEEKER','MAESTRO','MALE_SOLDIER','TROOPER','BERSEKER','MALE_SOULBREAKER','DOOMBRINGER','MALE_SOULDHOUND','FEMALE_SOLDIER','WARDER','FEMALE_SOULBREAKER','ARBALESTER','FEMALE_SOULDHOUND','TRICKSTER','INSPECTOR','JUDICATOR') NOT NULL DEFAULT 'HUMAN_FIGHTER', `sex` enum('MALE','FEMALE') NOT NULL, `level` int(3) NOT NULL, @@ -12,11 +12,20 @@ CREATE TABLE `character` ( `point_x` int(10) NOT NULL, `point_y` int(10) NOT NULL, `point_z` int(10) NOT NULL, - `point_angle` DOUBLE NOT NULL, + `point_angle` double NOT NULL, `appearance_hair_style` enum('STYLE_A','STYLE_B','STYLE_C','STYLE_D','STYLE_E') NOT NULL DEFAULT 'STYLE_A', `appearance_hair_color` enum('COLOR_A','COLOR_B','COLOR_C','COLOR_D') NOT NULL DEFAULT 'COLOR_A', `apperance_face` enum('FACE_A','FACE_B','FACE_C') NOT NULL DEFAULT 'FACE_A', PRIMARY KEY (`character_id`), KEY `account_id` (`account_id`), - KEY `name` (`name`) -) ENGINE=MyISAM; \ No newline at end of file + KEY `name` (`name`), + KEY `clan_id` (`clan_id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- +-- Temporary sample data +-- + +INSERT INTO `character` (`character_id`, `account_id`, `clan_id`, `name`, `race`, `class`, `sex`, `level`, `experience`, `sp`, `point_x`, `point_y`, `point_z`, `point_angle`, `appearance_hair_style`, `appearance_hair_color`, `apperance_face`) VALUES +(268437456, 'rogiel', NULL, 'Rogiel', 'HUMAN', 'HUMAN_FIGHTER', 'MALE', 1, 0, 0, -71338, 258271, -3104, 0, 'STYLE_B', 'COLOR_B', 'FACE_B'), +(268437457, 'rogiel2', NULL, 'Rogiel2', 'HUMAN', 'HUMAN_FIGHTER', 'MALE', 0, 0, 0, 0, 0, 0, 0, 'STYLE_A', 'COLOR_A', 'FACE_A'); diff --git a/src/main/resources/sql/character_shortcut.sql b/src/main/resources/sql/character_shortcut.sql new file mode 100644 index 000000000..f434f9323 --- /dev/null +++ b/src/main/resources/sql/character_shortcut.sql @@ -0,0 +1,12 @@ +CREATE TABLE IF NOT EXISTS `character_shortcut` ( + `character_id` int(10) NOT NULL, + `shortcut_id` int(10) DEFAULT NULL, + `slot` int(2) NOT NULL, + `page` int(1) NOT NULL, + `type` enum('ITEM','SKILL','ACTION','MACRO','RECIPE','TPBOOKMARK') NOT NULL, + `level` int(2) DEFAULT NULL, + `character_type` int(10) NOT NULL, + PRIMARY KEY (`character_id`,`slot`,`page`), + KEY `character_id` (`character_id`), + KEY `shortcut_id` (`shortcut_id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; \ No newline at end of file diff --git a/src/main/resources/sql/clan.sql b/src/main/resources/sql/clan.sql new file mode 100644 index 000000000..8cf3b35f6 --- /dev/null +++ b/src/main/resources/sql/clan.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS `clan` ( + `clan_id` int(10) NOT NULL, + `character_id_leader` int(10) NOT NULL, + PRIMARY KEY (`clan_id`), + KEY `character_id_leader` (`character_id_leader`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; \ No newline at end of file diff --git a/src/main/resources/sql/item.sql b/src/main/resources/sql/item.sql index f1931af07..48d6b3f34 100644 --- a/src/main/resources/sql/item.sql +++ b/src/main/resources/sql/item.sql @@ -1,7 +1,23 @@ -CREATE TABLE `item` ( +CREATE TABLE IF NOT EXISTS `item` ( `item_id` int(12) NOT NULL, `template_id` int(10) NOT NULL, - `character_id` int(12) NOT NULL, + `character_id` int(12) DEFAULT NULL, + `location` enum('PAPERDOLL','INVENTORY','WAREHOUSE') DEFAULT NULL, + `paperdoll` enum('UNDERWEAR','HEAD','HAIR1','HAIR2','NECK','RIGHT_HAND','CHEST','LEFT_HAND','RIGHT_EAR','LEFT_EAR','GLOVES','LEGS','FEET','RIGHT_FINGER','LEFT_FINGER','LEFT_BRACELET','RIGHT_BRACELET','DECORATION_1','DECORATION_2','DECORATION_3','DECORATION_4','DECORATION_5','DECORATION_6','CLOAK,BELT') DEFAULT NULL, + `count` int(10) NOT NULL, + `coord_x` int(10) DEFAULT NULL, + `coord_y` int(10) DEFAULT NULL, + `coord_z` int(10) DEFAULT NULL, PRIMARY KEY (`item_id`), - KEY `character_id` (`character_id`) -) ENGINE=MyISAM; \ No newline at end of file + KEY `character_id` (`character_id`), + KEY `template_id` (`template_id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +-- +-- Temporary sample data +-- + +INSERT INTO `item` (`item_id`, `template_id`, `character_id`, `location`, `paperdoll`, `count`, `coord_x`, `coord_y`, `coord_z`) VALUES +(268635457, 57, 268437456, 'INVENTORY', NULL, 200000000, NULL, NULL, NULL), +(268635459, 1, 268437456, 'PAPERDOLL', 'RIGHT_HAND', 1, NULL, NULL, NULL), +(268635460, 1, 268437456, 'INVENTORY', NULL, 1, NULL, NULL, NULL); diff --git a/src/main/resources/sql/npc_spawn.sql b/src/main/resources/sql/npc_spawn.sql new file mode 100644 index 000000000..bd4396ccc --- /dev/null +++ b/src/main/resources/sql/npc_spawn.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS `npc_spawn` ( + `npc_id` int(10) NOT NULL, + `point_x` int(10) NOT NULL, + `point_y` int(10) NOT NULL, + `point_z` int(10) NOT NULL, + `point_angle` double NOT NULL, + KEY `npc_id` (`npc_id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1; \ No newline at end of file