diff --git a/.classpath b/.classpath
new file mode 100644
index 00000000..b0f1625e
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 33cb509e..00000000
--- a/.gitignore
+++ /dev/null
@@ -1,11 +0,0 @@
-.project
-.classpath
-.idea/
-*.iml
-target/
-logs/
-log/
-test-output/
-hexid.txt
-
-.vscode/
\ No newline at end of file
diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar
deleted file mode 100644
index eebc3c18..00000000
Binary files a/.mvn/wrapper/maven-wrapper.jar and /dev/null differ
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
deleted file mode 100644
index e364bfe9..00000000
--- a/.mvn/wrapper/maven-wrapper.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-wrapperVersion=3.3.4
-distributionType=script
-distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.12/apache-maven-3.9.12-bin.zip
-wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.4/maven-wrapper-3.3.4.jar
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
deleted file mode 100644
index 04cfa2c1..00000000
--- a/.settings/org.eclipse.core.resources.prefs
+++ /dev/null
@@ -1,6 +0,0 @@
-eclipse.preferences.version=1
-encoding//src/main/java=UTF-8
-encoding//src/main/resources=UTF-8
-encoding//src/test/java=UTF-8
-encoding//src/test/resources=UTF-8
-encoding/=UTF-8
diff --git a/.settings/org.eclipse.jdt.apt.core.prefs b/.settings/org.eclipse.jdt.apt.core.prefs
deleted file mode 100644
index 8963047b..00000000
--- a/.settings/org.eclipse.jdt.apt.core.prefs
+++ /dev/null
@@ -1,4 +0,0 @@
-eclipse.preferences.version=1
-org.eclipse.jdt.apt.aptEnabled=true
-org.eclipse.jdt.apt.genSrcDir=target/generated-sources/annotations
-org.eclipse.jdt.apt.genTestSrcDir=target/generated-test-sources/test-annotations
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
deleted file mode 100644
index 3a5c6da3..00000000
--- a/.settings/org.eclipse.jdt.core.prefs
+++ /dev/null
@@ -1,525 +0,0 @@
-eclipse.preferences.version=1
-org.eclipse.jdt.core.builder.annotationPath.allLocations=disabled
-org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
-org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
-org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
-org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
-org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
-org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
-org.eclipse.jdt.core.compiler.annotation.notowning=org.eclipse.jdt.annotation.NotOwning
-org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
-org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
-org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
-org.eclipse.jdt.core.compiler.annotation.owning=org.eclipse.jdt.annotation.Owning
-org.eclipse.jdt.core.compiler.annotation.resourceanalysis=disabled
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=25
-org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=25
-org.eclipse.jdt.core.compiler.debug.lineNumber=generate
-org.eclipse.jdt.core.compiler.debug.localVariable=generate
-org.eclipse.jdt.core.compiler.debug.sourceFile=generate
-org.eclipse.jdt.core.compiler.problem.APILeak=warning
-org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated=info
-org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
-org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
-org.eclipse.jdt.core.compiler.problem.deadCode=warning
-org.eclipse.jdt.core.compiler.problem.deprecation=warning
-org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
-org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
-org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
-org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
-org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning
-org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
-org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
-org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
-org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
-org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
-org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
-org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
-org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
-org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
-org.eclipse.jdt.core.compiler.problem.incompatibleOwningContract=warning
-org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
-org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
-org.eclipse.jdt.core.compiler.problem.insufficientResourceAnalysis=warning
-org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
-org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
-org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
-org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
-org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
-org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
-org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
-org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
-org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
-org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
-org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
-org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
-org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
-org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
-org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
-org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
-org.eclipse.jdt.core.compiler.problem.nullReference=warning
-org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
-org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
-org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
-org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
-org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
-org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
-org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
-org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
-org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
-org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
-org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
-org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning
-org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning
-org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
-org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
-org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
-org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
-org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
-org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
-org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
-org.eclipse.jdt.core.compiler.problem.suppressWarningsNotFullyAnalysed=info
-org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
-org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning
-org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning
-org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
-org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled
-org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
-org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
-org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
-org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
-org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning
-org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled
-org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info
-org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning
-org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
-org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
-org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
-org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
-org.eclipse.jdt.core.compiler.problem.unusedImport=warning
-org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
-org.eclipse.jdt.core.compiler.problem.unusedLambdaParameter=warning
-org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
-org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
-org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
-org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
-org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
-org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning
-org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
-org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
-org.eclipse.jdt.core.compiler.processAnnotations=enabled
-org.eclipse.jdt.core.compiler.release=disabled
-org.eclipse.jdt.core.compiler.source=25
-org.eclipse.jdt.core.formatter.align_arrows_in_switch_on_columns=false
-org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
-org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
-org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line=true
-org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
-org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false
-org.eclipse.jdt.core.formatter.align_with_spaces=false
-org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
-org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant=49
-org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field=49
-org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable=49
-org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method=49
-org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package=49
-org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter=0
-org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type=49
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=48
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0
-org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0
-org.eclipse.jdt.core.formatter.alignment_for_assertion_message=0
-org.eclipse.jdt.core.formatter.alignment_for_assignment=4
-org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
-org.eclipse.jdt.core.formatter.alignment_for_compact_if=0
-org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16
-org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0
-org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0
-org.eclipse.jdt.core.formatter.alignment_for_enum_constants=49
-org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=49
-org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
-org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow=0
-org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon=0
-org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
-org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
-org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
-org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
-org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
-org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_permitted_types_in_type_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_record_components=0
-org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0
-org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=85
-org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=84
-org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0
-org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
-org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=48
-org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow=0
-org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0
-org.eclipse.jdt.core.formatter.alignment_for_type_annotations=0
-org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
-org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
-org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
-org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
-org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0
-org.eclipse.jdt.core.formatter.blank_lines_after_package=1
-org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1
-org.eclipse.jdt.core.formatter.blank_lines_before_field=0
-org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
-org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
-org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
-org.eclipse.jdt.core.formatter.blank_lines_before_method=1
-org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
-org.eclipse.jdt.core.formatter.blank_lines_before_package=0
-org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
-org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0
-org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
-org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_block_in_case_after_arrow=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_record_constructor=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_record_declaration=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
-org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
-org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=false
-org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false
-org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true
-org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=true
-org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false
-org.eclipse.jdt.core.formatter.comment.format_block_comments=true
-org.eclipse.jdt.core.formatter.comment.format_header=false
-org.eclipse.jdt.core.formatter.comment.format_html=true
-org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
-org.eclipse.jdt.core.formatter.comment.format_line_comments=true
-org.eclipse.jdt.core.formatter.comment.format_source_code=true
-org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
-org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
-org.eclipse.jdt.core.formatter.comment.indent_tag_description=false
-org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=do not insert
-org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert
-org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
-org.eclipse.jdt.core.formatter.comment.javadoc_do_not_separate_block_tags=false
-org.eclipse.jdt.core.formatter.comment.line_length=300
-org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
-org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
-org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
-org.eclipse.jdt.core.formatter.compact_else_if=true
-org.eclipse.jdt.core.formatter.continuation_indentation=1
-org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=1
-org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
-org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
-org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
-org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header=true
-org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
-org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
-org.eclipse.jdt.core.formatter.indent_empty_lines=true
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
-org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
-org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
-org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
-org.eclipse.jdt.core.formatter.indentation.size=4
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_label=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert
-org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
-org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert
-org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert
-org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
-org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_permitted_types=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
-org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
-org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
-org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
-org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
-org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
-org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
-org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
-org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert
-org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert
-org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_permitted_types=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
-org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
-org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
-org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
-org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
-org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
-org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
-org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
-org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
-org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
-org.eclipse.jdt.core.formatter.join_line_comments=false
-org.eclipse.jdt.core.formatter.join_lines_in_comments=true
-org.eclipse.jdt.core.formatter.join_wrapped_lines=false
-org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never
-org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never
-org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never
-org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
-org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=true
-org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never
-org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never
-org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never
-org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
-org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never
-org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never
-org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never
-org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line=one_line_never
-org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line=one_line_never
-org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false
-org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false
-org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false
-org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false
-org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line=one_line_never
-org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line=one_line_never
-org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
-org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never
-org.eclipse.jdt.core.formatter.lineSplit=320
-org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
-org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
-org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block=0
-org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0
-org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
-org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=0
-org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=0
-org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0
-org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
-org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
-org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
-org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
-org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
-org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
-org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
-org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
-org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
-org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration=common_lines
-org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
-org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
-org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false
-org.eclipse.jdt.core.formatter.tabulation.char=tab
-org.eclipse.jdt.core.formatter.tabulation.size=4
-org.eclipse.jdt.core.formatter.text_block_indentation=0
-org.eclipse.jdt.core.formatter.use_on_off_tags=true
-org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
-org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
-org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator=true
-org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
-org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
-org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
-org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true
-org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
-org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
-org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true
-org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true
-org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
-org.eclipse.jdt.core.formatter.wrap_before_switch_case_arrow_operator=false
-org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
-org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs
deleted file mode 100644
index 6a5a2714..00000000
--- a/.settings/org.eclipse.jdt.ui.prefs
+++ /dev/null
@@ -1,147 +0,0 @@
-cleanup.add_all=true
-cleanup.add_default_serial_version_id=false
-cleanup.add_generated_serial_version_id=true
-cleanup.add_missing_annotations=true
-cleanup.add_missing_deprecated_annotations=true
-cleanup.add_missing_methods=true
-cleanup.add_missing_nls_tags=false
-cleanup.add_missing_override_annotations=true
-cleanup.add_missing_override_annotations_interface_methods=true
-cleanup.add_serial_version_id=true
-cleanup.also_simplify_lambda=true
-cleanup.always_use_blocks=true
-cleanup.always_use_parentheses_in_expressions=true
-cleanup.always_use_this_for_non_static_field_access=false
-cleanup.always_use_this_for_non_static_method_access=false
-cleanup.array_with_curly=false
-cleanup.arrays_fill=false
-cleanup.bitwise_conditional_expression=false
-cleanup.boolean_literal=true
-cleanup.boolean_value_rather_than_comparison=true
-cleanup.break_loop=false
-cleanup.collection_cloning=false
-cleanup.comparing_on_criteria=false
-cleanup.comparison_statement=true
-cleanup.controlflow_merge=false
-cleanup.convert_functional_interfaces=true
-cleanup.convert_to_enhanced_for_loop=true
-cleanup.convert_to_enhanced_for_loop_if_loop_var_used=true
-cleanup.convert_to_switch_expressions=true
-cleanup.correct_indentation=false
-cleanup.do_while_rather_than_while=true
-cleanup.double_negation=true
-cleanup.else_if=false
-cleanup.embedded_if=false
-cleanup.evaluate_nullable=false
-cleanup.extract_increment=false
-cleanup.format_source_code=true
-cleanup.format_source_code_changes_only=false
-cleanup.hash=false
-cleanup.if_condition=true
-cleanup.insert_inferred_type_arguments=false
-cleanup.instanceof=true
-cleanup.instanceof_keyword=true
-cleanup.invert_equals=false
-cleanup.join=true
-cleanup.lazy_logical_operator=true
-cleanup.make_local_variable_final=false
-cleanup.make_parameters_final=false
-cleanup.make_private_fields_final=true
-cleanup.make_type_abstract_if_missing_method=false
-cleanup.make_variable_declarations_final=true
-cleanup.map_cloning=false
-cleanup.merge_conditional_blocks=false
-cleanup.multi_catch=false
-cleanup.never_use_blocks=false
-cleanup.never_use_parentheses_in_expressions=false
-cleanup.no_string_creation=true
-cleanup.no_super=true
-cleanup.number_suffix=false
-cleanup.objects_equals=false
-cleanup.one_if_rather_than_duplicate_blocks_that_fall_through=false
-cleanup.operand_factorization=false
-cleanup.organize_imports=true
-cleanup.overridden_assignment=false
-cleanup.overridden_assignment_move_decl=true
-cleanup.plain_replacement=true
-cleanup.precompile_regex=true
-cleanup.primitive_comparison=true
-cleanup.primitive_parsing=true
-cleanup.primitive_rather_than_wrapper=true
-cleanup.primitive_serialization=true
-cleanup.pull_out_if_from_if_else=true
-cleanup.pull_up_assignment=false
-cleanup.push_down_negation=false
-cleanup.qualify_static_field_accesses_with_declaring_class=false
-cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
-cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
-cleanup.qualify_static_member_accesses_with_declaring_class=true
-cleanup.qualify_static_method_accesses_with_declaring_class=false
-cleanup.reduce_indentation=false
-cleanup.redundant_comparator=true
-cleanup.redundant_falling_through_block_end=false
-cleanup.remove_private_constructors=true
-cleanup.remove_redundant_modifiers=true
-cleanup.remove_redundant_semicolons=true
-cleanup.remove_redundant_type_arguments=true
-cleanup.remove_trailing_whitespaces=false
-cleanup.remove_trailing_whitespaces_all=true
-cleanup.remove_trailing_whitespaces_ignore_empty=true
-cleanup.remove_unnecessary_array_creation=false
-cleanup.remove_unnecessary_casts=true
-cleanup.remove_unnecessary_nls_tags=true
-cleanup.remove_unused_imports=true
-cleanup.remove_unused_local_variables=true
-cleanup.remove_unused_method_parameters=false
-cleanup.remove_unused_private_fields=true
-cleanup.remove_unused_private_members=true
-cleanup.remove_unused_private_methods=true
-cleanup.remove_unused_private_types=true
-cleanup.return_expression=false
-cleanup.simplify_lambda_expression_and_method_ref=true
-cleanup.single_used_field=false
-cleanup.sort_members=false
-cleanup.sort_members_all=false
-cleanup.standard_comparison=false
-cleanup.static_inner_class=true
-cleanup.strictly_equal_or_different=false
-cleanup.stringbuffer_to_stringbuilder=true
-cleanup.stringbuilder=true
-cleanup.stringbuilder_for_local_vars=true
-cleanup.stringconcat_stringbuffer_stringbuilder=false
-cleanup.stringconcat_to_textblock=false
-cleanup.substring=true
-cleanup.switch=false
-cleanup.system_property=false
-cleanup.system_property_boolean=false
-cleanup.system_property_file_encoding=false
-cleanup.system_property_file_separator=false
-cleanup.system_property_line_separator=false
-cleanup.system_property_path_separator=false
-cleanup.ternary_operator=false
-cleanup.try_with_resource=false
-cleanup.unlooped_while=false
-cleanup.unreachable_block=false
-cleanup.use_anonymous_class_creation=false
-cleanup.use_autoboxing=false
-cleanup.use_blocks=true
-cleanup.use_blocks_only_for_return_and_throw=false
-cleanup.use_directly_map_method=true
-cleanup.use_lambda=true
-cleanup.use_parentheses_in_expressions=true
-cleanup.use_string_is_blank=true
-cleanup.use_this_for_non_static_field_access=true
-cleanup.use_this_for_non_static_field_access_only_if_necessary=true
-cleanup.use_this_for_non_static_method_access=true
-cleanup.use_this_for_non_static_method_access_only_if_necessary=true
-cleanup.use_unboxing=false
-cleanup.use_var=false
-cleanup.useless_continue=false
-cleanup.useless_return=false
-cleanup.valueof_rather_than_instantiation=true
-cleanup_profile=_L2J Clean Up v0.5
-cleanup_settings_version=2
-eclipse.preferences.version=1
-formatter_profile=_L2J Formatter v0.9
-formatter_settings_version=23
-org.eclipse.jdt.ui.text.custom_code_templates=
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs
deleted file mode 100644
index 14b697b7..00000000
--- a/.settings/org.eclipse.m2e.core.prefs
+++ /dev/null
@@ -1,4 +0,0 @@
-activeProfiles=
-eclipse.preferences.version=1
-resolveWorkspaceProjects=true
-version=1
diff --git a/L2J_Server/.classpath b/L2J_Server/.classpath
new file mode 100644
index 00000000..66fb4ee0
--- /dev/null
+++ b/L2J_Server/.classpath
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Server/.gitignore b/L2J_Server/.gitignore
new file mode 100644
index 00000000..707caf28
--- /dev/null
+++ b/L2J_Server/.gitignore
@@ -0,0 +1,2 @@
+/bin/
+/build/
diff --git a/L2J_Server/.project b/L2J_Server/.project
new file mode 100644
index 00000000..e04bf58f
--- /dev/null
+++ b/L2J_Server/.project
@@ -0,0 +1,19 @@
+
+
+ L2J_Server
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jem.workbench.JavaEMFNature
+ org.eclipse.jdt.core.javanature
+ org.eclipse.jem.beaninfo.BeanInfoNature
+
+
\ No newline at end of file
diff --git a/L2J_Server/.settings/org.eclipse.core.resources.prefs b/L2J_Server/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 00000000..4824b802
--- /dev/null
+++ b/L2J_Server/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/L2J_Server/.settings/org.eclipse.core.runtime.prefs b/L2J_Server/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 00000000..f8a67de1
--- /dev/null
+++ b/L2J_Server/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\r\n
diff --git a/L2J_Server/.settings/org.eclipse.jdt.core.prefs b/L2J_Server/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000..03505355
--- /dev/null
+++ b/L2J_Server/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,390 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=disabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=disabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=48
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0
+org.eclipse.jdt.core.formatter.alignment_for_assignment=4
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=0
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=49
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=49
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=48
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=next_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=next_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=true
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=do not insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=300
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=1
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=1
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=true
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=300
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=false
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=true
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/L2J_Server/.settings/org.eclipse.jdt.ui.prefs b/L2J_Server/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 00000000..66adcee1
--- /dev/null
+++ b/L2J_Server/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,125 @@
+cleanup.add_default_serial_version_id=false
+cleanup.add_generated_serial_version_id=true
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=true
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=true
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=true
+cleanup.convert_to_enhanced_for_loop=true
+cleanup.correct_indentation=false
+cleanup.format_source_code=true
+cleanup.format_source_code_changes_only=false
+cleanup.make_local_variable_final=false
+cleanup.make_parameters_final=false
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=true
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=true
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=true
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=true
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup_profile=_L2J Clean Up v0.3
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_L2J Formatter v0.4
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;org;com;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=false
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=/**\r\n * @return the ${bare_field_name}\r\n *//**\r\n * @param ${param} the ${bare_field_name} to set\r\n *//**\r\n * ${tags}\r\n *//*\r\n * Copyright (C) 2004-${year} L2J Server\r\n * \r\n * This file is part of L2J Server.\r\n * \r\n * L2J Server is free software\: you can redistribute it and/or modify\r\n * it under the terms of the GNU General Public License as published by\r\n * the Free Software Foundation, either version 3 of the License, or\r\n * (at your option) any later version.\r\n * \r\n * L2J Server is distributed in the hope that it will be useful,\r\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r\n * General Public License for more details.\r\n * \r\n * You should have received a copy of the GNU General Public License\r\n * along with this program. If not, see <http\://www.gnu.org/licenses/>.\r\n *//**\r\n * @author ${user}\r\n *\r\n * ${tags}\r\n *//**\r\n * \r\n *//**\r\n * ${tags}\r\n *//* (non-Javadoc)\r\n * ${see_to_overridden}\r\n *//**\r\n * ${tags}\r\n * ${see_to_target}\r\n */${filecomment}\r\n${package_declaration}\r\n\r\n${typecomment}\r\n${type_declaration}\r\n\r\n\r\n\r\n// ${todo} Auto-generated catch block\r\n${exception_var}.printStackTrace();// ${todo} Auto-generated method stub\r\n${body_statement}${body_statement}\r\n// ${todo} Auto-generated constructor stubreturn ${field};${field} \= ${param};
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=true
+sp_cleanup.convert_to_enhanced_for_loop=true
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=true
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.make_local_variable_final=false
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=true
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=true
+sp_cleanup.remove_unused_imports=true
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=true
+sp_cleanup.use_parentheses_in_expressions=true
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
diff --git a/L2J_Server/.settings/org.eclipse.wst.sse.core.prefs b/L2J_Server/.settings/org.eclipse.wst.sse.core.prefs
new file mode 100644
index 00000000..a640cfdb
--- /dev/null
+++ b/L2J_Server/.settings/org.eclipse.wst.sse.core.prefs
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+task-tags/enabled=true
+task-tags/use-project-settings=true
diff --git a/L2J_Server/.settings/org.eclipse.wst.validation.prefs b/L2J_Server/.settings/org.eclipse.wst.validation.prefs
new file mode 100644
index 00000000..63a18689
--- /dev/null
+++ b/L2J_Server/.settings/org.eclipse.wst.validation.prefs
@@ -0,0 +1,12 @@
+DELEGATES_PREFERENCE=delegateValidatorList
+USER_BUILD_PREFERENCE=enabledBuildValidatorList
+USER_MANUAL_PREFERENCE=enabledManualValidatorList
+USER_PREFERENCE=overrideGlobalPreferencestruedisableAllValidationfalseversion1.2.400.v201204260100
+eclipse.preferences.version=1
+override=true
+suspend=false
+vals/org.eclipse.wst.dtd.core.dtdDTDValidator/global=FF01
+vals/org.eclipse.wst.html.core.HTMLValidator/global=FF01
+vals/org.eclipse.wst.html.ui.HTMLValidator/global=TF01
+vals/org.eclipse.wst.xml.core.xml/groups=0107include05111contentType128org.eclipse.core.runtime.xmlT111contentType134org.eclipse.wst.xml.core.xmlsourceT111contentType134org.eclipse.wst.xml.core.xslsourceT111contentType134org.eclipse.jst.jsp.core.tldsourceT07fileext03xmlF0107exclude08113projectNature134org.eclipse.jst.j2ee.ejb.EJBNature113projectNature130org.eclipse.jst.j2ee.EARNature04file08.projectT0104file110.classpathT0104file110.settings/T0204file03binF0204file05buildF0204file09build.xmlF01
+vf.version=3
diff --git a/L2J_Server/build.xml b/L2J_Server/build.xml
new file mode 100644
index 00000000..5938e70d
--- /dev/null
+++ b/L2J_Server/build.xml
@@ -0,0 +1,135 @@
+
+
+
+ This script will build the L2J Server.
+
+ This program 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, 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ http://www.gnu.org/copyleft/gpl.html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${l2j.changelog}
+
+
+
+ version=${l2j.version}${line.separator}builddate=${build.tstamp}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Server/dist/doc/L2J_Server_LICENSE.txt b/L2J_Server/dist/doc/L2J_Server_LICENSE.txt
new file mode 100644
index 00000000..3d90694a
--- /dev/null
+++ b/L2J_Server/dist/doc/L2J_Server_LICENSE.txt
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program 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.
+
+ 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
\ No newline at end of file
diff --git a/L2J_Server/dist/doc/L2J_Server_README.txt b/L2J_Server/dist/doc/L2J_Server_README.txt
new file mode 100644
index 00000000..fd944620
--- /dev/null
+++ b/L2J_Server/dist/doc/L2J_Server_README.txt
@@ -0,0 +1,292 @@
+NOTE: This short guide is for a L2J Server. http://l2jserver.com
+
+If you received this file as a part of a packaged or bundled build:
+
+L2J only supports L2J software obtained directly from L2J sources.
+
+What this means is, if you obtained L2J from a source other than our SVN or nightly distribution,
+you need to get support from where you got the files.
+We are unable to provide any technical assistance for unsupported software packages.
+The software may have viruses, cause security problems,
+or even send your personal information to remote servers without your express consent.
+We cannot recommend the use of any of these packages on a server.
+
+WARNING: L2J Server is not a plug and play type of server.
+To setup the server and to run it successfully you need to do a lot of reading.
+If reading and learning are not something you like to do,
+Stop now.
+
+====================
+L2J Server
+====================
+$Date: 2010/01/06 13:12:11 $
+
+TOC:
+I. OVERVIEW
+II. LEGAL
+III. REQUIREMENTS
+IV. FIRST STARTUP
+V. ADMIN/GM's GUIDE
+VI. PLAYER's GUIDE
+VII. UPDATING
+VIII. TROUBLESHOOTING
+IX. CONTACT
+X. CONTRIBUTING
+XI. BUG REPORTING
+XII. CREDITS
+
+
+
+====================
+I. OVERVIEW
+====================
+
+L2J is an Alternative Lineage 2 Game Server written in pure Java for
+best compatibility. L2J gives you the possibility to legally host a game
+server for this popular Korean MMO created by NCSoft. It is still
+unfinished and many features are missing, but L2J Dev team is working
+hard on implementing them. L2J Server is distributed under the terms
+of GNU/GPL in a hope that open source model is the best for
+developing quality software giving everyone a possibility to
+participate on development by submitting the code.
+
+
+====================
+II. LEGAL
+====================
+
+This program 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, 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
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+USA.
+
+Full GNU/GPL License is included in LICENSE.TXT file.
+
+Whereas L2J is distributed under the terms of GNU/GPL, we require you to:
+a) Preserve login notice. This gives us, L2J Developers, appropriate
+credit for our hard work done during our free time without any
+revenues.
+
+b) Do not distribute any extended data files with the server files in
+the same archive. NO world content should be incorporated in L2J
+distribution.
+Server and Datapack may not be not be bundled or packaged.
+
+====================
+III. REQUIREMENTS
+====================
+
+OS:
+Any OS having Java JDK 1.6 installed and properly configured!
+ We recommend using SUN JDK available at java.sun.com
+
+Hardware:
+Decent CPU & RAM
+
+Software:
+Java JDK 1.6
+MySql
+Datapack
+
+We recommend:
+That you do not play and host the server from the same computer.
+Have a good Internet connection - dial up just won't cut it.
+Many low cost hosting options are available.
+
+====================
+IV. FIRST STARTUP
+====================
+
+Before you can start up the server it is extremely important to read
+and get to know the wiki sites.
+They contain all the info you need to setup and run a L2J Server.
+
+L2J Server wiki: Server Guides, How-to's, bugtracker:
+https://www.l2jserver.com/trac/wiki
+
+L2J-Datapack wiki: Datapack Guides, How-to's, bugtracker:
+http://www.l2jdp.com/trac/wiki
+
+This Server distribution does not contain any spawn/drop data or any world
+content. (Datapack)
+
+L2J Server has also a possibility to change exp/sp/drop rates relative
+to data in spawnlist/droplist files. To do that, just change the rates
+you need in server.properties file found in config folder.
+
+You should also configure your IP address in server.properties.
+
+Server uses ports 2106 (LoginServer) and 7777 (GameServer) by
+default. If your server runs behind NAT or firewall you will need to
+open and/or forward these ports.
+
+
+====================
+V. ADMIN/GM's GUIDE
+====================
+
+To make someone an admin you need to edit, in the l2jdb database, the desired character in the
+characters table, while server is SHUT DOWN! Change the field, accesslevel from 0 to 100 or more.
+You may start server after that and the person will have admin privileges.
+Note that you must create the account and character before editing.
+
+Possible access levels:
+-100 = banned
+0 = normal account/character
+51 or more = exempt from maximum connections limit (accounts table only)
+100 or more = admin
+
+More info can be found in the community wiki.
+
+Admin commands implemented:
+(Please see https://l2jserver.com/trac/wiki/GmCommands for more complete list.)
+//admin = main GM interface
+//gmchat = will send a message to all online GMs
+//invul = makes your character untouchable
+
+====================
+VI. PLAYER's GUIDE
+====================
+
+CLIENT COMPATIBILITY
+Our server is dependent on the official release of the North American lineage2 live client.
+http://www.lineage2.com
+All help and support will only be for the official client.
+Any clients obtained elsewhere, must obtain support from where it was obtained.
+
+====================
+VI. UPDATING
+====================
+It may arrive that you want to update your server to new version while
+keeping old accounts. There are few steps you HAVE TO do in order to
+keep the data accurate.
+
+- You should ALWAYS look at timelines before updating, sometimes a file
+ format may change, so you will need to edit data manually to fit with
+ new format.
+- You should ALWAYS Backup all MySql data.
+- You should ALWAYS Backup all Server and Datapack files.
+- back up all .properties files (don't forget to check if new server use same
+ format for those files)
+- download & unzip new server code to the Server directory
+- download & unzip new datapack code to the Server directory
+- edit and run update in the tools folder
+- run newly installed server & enjoy ;)
+
+
+====================
+VIII. TROUBLESHOOTING
+====================
+
+PROBLEM
+- Client outputs bunch of messages about missing templates.
+SOLUTION
+- Check that the datapack has been properly installed.
+
+PROBLEM
+- Message similar to "java is not recognized as internal command",
+"java not found" or "unknown command: java" appears.
+SOLUTION
+- Install java, or, if java is already installed just add your java
+binary directory to system PATH setting. If you don't know how to do
+that, than DO NOT bother running your own server please.
+
+PROBLEM
+- I can log in but ping is 9999s and I can't get past Server Select.
+SOLUTION
+- Set up your IP's properly, forward/open good ports if accessing from
+outside. (or find server with admin that knows how to do it)
+
+PROBLEM
+- Skills/quests/whatever don't work.
+SOLUTION
+- Patience brings it's fruits :p
+
+PROBLEM
+- I found a bug.
+SOLUTION
+- Please refer to BUG REPORTING section of this read-me.
+
+Further help available at the wiki sites and the forums.
+
+
+====================
+IX. CONTACT
+====================
+
+Website: http://www.l2jserver.com
+Forum: http://www.l2jserver.com/forum
+IRC: #l2j @ Freenode (irc.freenode.net)
+
+Please note that L2J Devs can't help players with connecting issues or
+anything related to playing on private servers. If you can't connect,
+you should contact your server GM's. We can solve only L2J server
+~software~ related issues. We don't have any backdoors or anything
+that would enable us GM accounts on every server using L2J, so there's
+no point in coming to our channel if you need items/adena/whatever
+ingame.
+
+
+====================
+X. CONTRIBUTING
+====================
+
+Anyone who wants to contribute to the project is encouraged to do so. Java
+programming skills are not always required as L2J needs much more than
+java code.
+
+If you created any source code that may be helpful please use the User Contributions
+section on our forums. If you contributed good stuff that will be
+accepted, you might be invited to join L2J Dev Team.
+
+People willing to hang on chat and respond to user questions are also
+ALWAYS welcome ;)
+
+
+====================
+XI. BUG REPORTING
+====================
+
+Bugs can be reported on our wiki site.
+http://l2jserver.com/trac/newticket
+Basic rules for reporting are:
+ Please report only one bug/issue per ticket!!
+ You must include the revision (changeset) number when reporting a bug!
+ "The latest" does not mean anything when 5 more updates have been done since you set up the server.
+If you are not sure if it should be reported here, make a post about it in the L2J forum.
+
+Players should ALWAYS consult bugs with their Admin/GM's and have them report it
+on our wiki site. Some bugs may be caused by bad datapack, server
+installation or modifications server owner has made. We can't help you
+in that case.
+
+Please use the datapacks bugtracker for reporting datapack bugs.
+Please do NOT report bugs related to unofficial add-ons to L2J. L2J
+bugtracker is NOT a place to fix that. Contact the person who made
+modification instead.
+
+
+====================
+XII. CREDITS
+====================
+
+Dev team:
+http://www.l2jserver.com/forum/memberlist.php?mode=leaders
+
+Have fun playing L2J ;)
+Dev Team
+
+ L2J Server, Copyright (C) 2006-2010
+ L2J Server comes with ABSOLUTELY NO WARRANTY.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions.
\ No newline at end of file
diff --git a/L2J_Server/dist/doc/bsh-engine_LICENSE.txt b/L2J_Server/dist/doc/bsh-engine_LICENSE.txt
new file mode 100644
index 00000000..51202573
--- /dev/null
+++ b/L2J_Server/dist/doc/bsh-engine_LICENSE.txt
@@ -0,0 +1,32 @@
+Copyright (c) 2006, Sun Microsystems, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ - Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ - Neither the name of the Sun Microsystems, Inc. nor the names of
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
diff --git a/L2J_Server/dist/doc/c3p0_LICENSE.txt b/L2J_Server/dist/doc/c3p0_LICENSE.txt
new file mode 100644
index 00000000..f5b77022
--- /dev/null
+++ b/L2J_Server/dist/doc/c3p0_LICENSE.txt
@@ -0,0 +1,502 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This library 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 2.1 of the License, or (at your option) any later version.
+
+ This library 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 library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ , 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
\ No newline at end of file
diff --git a/L2J_Server/dist/doc/ecj_LICENSE.html b/L2J_Server/dist/doc/ecj_LICENSE.html
new file mode 100644
index 00000000..e52bf6e2
--- /dev/null
+++ b/L2J_Server/dist/doc/ecj_LICENSE.html
@@ -0,0 +1,28 @@
+
+
+
+
+About
+
+
+
About This Content
+
+
June 2, 2006
+
License
+
+
The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at http://www.eclipse.org/legal/epl-v10.html.
+For purposes of the EPL, "Program" will mean the Content.
+
+
If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at http://www.eclipse.org.
+ * For all Tasks that should be executed with no delay asynchronously in a ThreadPool there also are usual {@link ThreadPoolExecutor ThreadPools} that can grow/shrink according to their load.:
+ *
+ *
{@link #_generalPacketsThreadPool GeneralPackets} where most packets handler are executed.
+ *
{@link #_ioPacketsThreadPool I/O Packets} where all the i/o packets are executed.
+ *
There will be an AI ThreadPool where AI events should be executed
+ *
A general ThreadPool where everything else that needs to run asynchronously with no delay should be executed ({@link com.l2jserver.gameserver.model.actor.knownlist KnownList} updates, SQL updates/inserts...)?
+ *
+ *
+ * @author -Wooden-
+ */
+public class ThreadPoolManager
+{
+ protected static final Logger _log = Logger.getLogger(ThreadPoolManager.class.getName());
+
+ private static final class RunnableWrapper implements Runnable
+ {
+ private final Runnable _r;
+
+ public RunnableWrapper(final Runnable r)
+ {
+ _r = r;
+ }
+
+ @Override
+ public final void run()
+ {
+ try
+ {
+ _r.run();
+ }
+ catch (final Throwable e)
+ {
+ final Thread t = Thread.currentThread();
+ final UncaughtExceptionHandler h = t.getUncaughtExceptionHandler();
+ if (h != null)
+ {
+ h.uncaughtException(t, e);
+ }
+ }
+ }
+ }
+
+ protected final ScheduledThreadPoolExecutor _effectsScheduledThreadPool;
+ protected final ScheduledThreadPoolExecutor _generalScheduledThreadPool;
+ protected final ScheduledThreadPoolExecutor _aiScheduledThreadPool;
+ private final ThreadPoolExecutor _generalPacketsThreadPool;
+ private final ThreadPoolExecutor _ioPacketsThreadPool;
+ private final ThreadPoolExecutor _generalThreadPool;
+
+ /** temp workaround for VM issue */
+ private static final long MAX_DELAY = Long.MAX_VALUE / 1000000 / 2;
+
+ private boolean _shutdown;
+
+ public static ThreadPoolManager getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ private ThreadPoolManager()
+ {
+ _effectsScheduledThreadPool = new ScheduledThreadPoolExecutor(Config.THREAD_P_EFFECTS, new PriorityThreadFactory("EffectsSTPool", Thread.NORM_PRIORITY));
+ _generalScheduledThreadPool = new ScheduledThreadPoolExecutor(Config.THREAD_P_GENERAL, new PriorityThreadFactory("GeneralSTPool", Thread.NORM_PRIORITY));
+ _ioPacketsThreadPool = new ThreadPoolExecutor(Config.IO_PACKET_THREAD_CORE_SIZE, Integer.MAX_VALUE, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue(), new PriorityThreadFactory("I/O Packet Pool", Thread.NORM_PRIORITY + 1));
+ _generalPacketsThreadPool = new ThreadPoolExecutor(Config.GENERAL_PACKET_THREAD_CORE_SIZE, Config.GENERAL_PACKET_THREAD_CORE_SIZE + 2, 15L, TimeUnit.SECONDS, new LinkedBlockingQueue(), new PriorityThreadFactory("Normal Packet Pool", Thread.NORM_PRIORITY + 1));
+ _generalThreadPool = new ThreadPoolExecutor(Config.GENERAL_THREAD_CORE_SIZE, Config.GENERAL_THREAD_CORE_SIZE + 2, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue(), new PriorityThreadFactory("General Pool", Thread.NORM_PRIORITY));
+ _aiScheduledThreadPool = new ScheduledThreadPoolExecutor(Config.AI_MAX_THREAD, new PriorityThreadFactory("AISTPool", Thread.NORM_PRIORITY));
+
+ scheduleGeneralAtFixedRate(new PurgeTask(), 10 * 60 * 1000l, 5 * 60 * 1000l);
+ }
+
+ public static long validateDelay(long delay)
+ {
+ if (delay < 0)
+ {
+ delay = 0;
+ }
+ else if (delay > MAX_DELAY)
+ {
+ delay = MAX_DELAY;
+ }
+ return delay;
+ }
+
+ public ScheduledFuture> scheduleEffect(Runnable r, long delay)
+ {
+ try
+ {
+ delay = ThreadPoolManager.validateDelay(delay);
+ return _effectsScheduledThreadPool.schedule(new RunnableWrapper(r), delay, TimeUnit.MILLISECONDS);
+ }
+ catch (RejectedExecutionException e)
+ {
+ return null;
+ }
+ }
+
+ public ScheduledFuture> scheduleEffectAtFixedRate(Runnable r, long initial, long delay)
+ {
+ try
+ {
+ delay = ThreadPoolManager.validateDelay(delay);
+ initial = ThreadPoolManager.validateDelay(initial);
+ return _effectsScheduledThreadPool.scheduleAtFixedRate(new RunnableWrapper(r), initial, delay, TimeUnit.MILLISECONDS);
+ }
+ catch (RejectedExecutionException e)
+ {
+ return null; /* shutdown, ignore */
+ }
+ }
+
+ @Deprecated
+ public boolean removeEffect(RunnableScheduledFuture> r)
+ {
+ return _effectsScheduledThreadPool.remove(r);
+ }
+
+ public ScheduledFuture> scheduleGeneral(Runnable r, long delay)
+ {
+ try
+ {
+ delay = ThreadPoolManager.validateDelay(delay);
+ return _generalScheduledThreadPool.schedule(new RunnableWrapper(r), delay, TimeUnit.MILLISECONDS);
+ }
+ catch (RejectedExecutionException e)
+ {
+ return null; /* shutdown, ignore */
+ }
+ }
+
+ public ScheduledFuture> scheduleGeneralAtFixedRate(Runnable r, long initial, long delay)
+ {
+ try
+ {
+ delay = ThreadPoolManager.validateDelay(delay);
+ initial = ThreadPoolManager.validateDelay(initial);
+ return _generalScheduledThreadPool.scheduleAtFixedRate(new RunnableWrapper(r), initial, delay, TimeUnit.MILLISECONDS);
+ }
+ catch (RejectedExecutionException e)
+ {
+ return null; /* shutdown, ignore */
+ }
+ }
+
+ @Deprecated
+ public boolean removeGeneral(RunnableScheduledFuture> r)
+ {
+ return _generalScheduledThreadPool.remove(r);
+ }
+
+ public ScheduledFuture> scheduleAi(Runnable r, long delay)
+ {
+ try
+ {
+ delay = ThreadPoolManager.validateDelay(delay);
+ return _aiScheduledThreadPool.schedule(new RunnableWrapper(r), delay, TimeUnit.MILLISECONDS);
+ }
+ catch (RejectedExecutionException e)
+ {
+ return null; /* shutdown, ignore */
+ }
+ }
+
+ public ScheduledFuture> scheduleAiAtFixedRate(Runnable r, long initial, long delay)
+ {
+ try
+ {
+ delay = ThreadPoolManager.validateDelay(delay);
+ initial = ThreadPoolManager.validateDelay(initial);
+ return _aiScheduledThreadPool.scheduleAtFixedRate(new RunnableWrapper(r), initial, delay, TimeUnit.MILLISECONDS);
+ }
+ catch (RejectedExecutionException e)
+ {
+ return null; /* shutdown, ignore */
+ }
+ }
+
+ public void executePacket(Runnable pkt)
+ {
+ _generalPacketsThreadPool.execute(pkt);
+ }
+
+ public void executeCommunityPacket(Runnable r)
+ {
+ _generalPacketsThreadPool.execute(r);
+ }
+
+ public void executeIOPacket(Runnable pkt)
+ {
+ _ioPacketsThreadPool.execute(pkt);
+ }
+
+ public void executeTask(Runnable r)
+ {
+ _generalThreadPool.execute(r);
+ }
+
+ public void executeAi(Runnable r)
+ {
+ _aiScheduledThreadPool.execute(new RunnableWrapper(r));
+ }
+
+ public String[] getStats()
+ {
+ return new String[]
+ {
+ "STP:",
+ " + Effects:",
+ " |- ActiveThreads: " + _effectsScheduledThreadPool.getActiveCount(),
+ " |- getCorePoolSize: " + _effectsScheduledThreadPool.getCorePoolSize(),
+ " |- PoolSize: " + _effectsScheduledThreadPool.getPoolSize(),
+ " |- MaximumPoolSize: " + _effectsScheduledThreadPool.getMaximumPoolSize(),
+ " |- CompletedTasks: " + _effectsScheduledThreadPool.getCompletedTaskCount(),
+ " |- ScheduledTasks: " + (_effectsScheduledThreadPool.getTaskCount() - _effectsScheduledThreadPool.getCompletedTaskCount()),
+ " | -------",
+ " + General:",
+ " |- ActiveThreads: " + _generalScheduledThreadPool.getActiveCount(),
+ " |- getCorePoolSize: " + _generalScheduledThreadPool.getCorePoolSize(),
+ " |- PoolSize: " + _generalScheduledThreadPool.getPoolSize(),
+ " |- MaximumPoolSize: " + _generalScheduledThreadPool.getMaximumPoolSize(),
+ " |- CompletedTasks: " + _generalScheduledThreadPool.getCompletedTaskCount(),
+ " |- ScheduledTasks: " + (_generalScheduledThreadPool.getTaskCount() - _generalScheduledThreadPool.getCompletedTaskCount()),
+ " | -------",
+ " + AI:",
+ " |- ActiveThreads: " + _aiScheduledThreadPool.getActiveCount(),
+ " |- getCorePoolSize: " + _aiScheduledThreadPool.getCorePoolSize(),
+ " |- PoolSize: " + _aiScheduledThreadPool.getPoolSize(),
+ " |- MaximumPoolSize: " + _aiScheduledThreadPool.getMaximumPoolSize(),
+ " |- CompletedTasks: " + _aiScheduledThreadPool.getCompletedTaskCount(),
+ " |- ScheduledTasks: " + (_aiScheduledThreadPool.getTaskCount() - _aiScheduledThreadPool.getCompletedTaskCount()),
+ "TP:",
+ " + Packets:",
+ " |- ActiveThreads: " + _generalPacketsThreadPool.getActiveCount(),
+ " |- getCorePoolSize: " + _generalPacketsThreadPool.getCorePoolSize(),
+ " |- MaximumPoolSize: " + _generalPacketsThreadPool.getMaximumPoolSize(),
+ " |- LargestPoolSize: " + _generalPacketsThreadPool.getLargestPoolSize(),
+ " |- PoolSize: " + _generalPacketsThreadPool.getPoolSize(),
+ " |- CompletedTasks: " + _generalPacketsThreadPool.getCompletedTaskCount(),
+ " |- QueuedTasks: " + _generalPacketsThreadPool.getQueue().size(),
+ " | -------",
+ " + I/O Packets:",
+ " |- ActiveThreads: " + _ioPacketsThreadPool.getActiveCount(),
+ " |- getCorePoolSize: " + _ioPacketsThreadPool.getCorePoolSize(),
+ " |- MaximumPoolSize: " + _ioPacketsThreadPool.getMaximumPoolSize(),
+ " |- LargestPoolSize: " + _ioPacketsThreadPool.getLargestPoolSize(),
+ " |- PoolSize: " + _ioPacketsThreadPool.getPoolSize(),
+ " |- CompletedTasks: " + _ioPacketsThreadPool.getCompletedTaskCount(),
+ " |- QueuedTasks: " + _ioPacketsThreadPool.getQueue().size(),
+ " | -------",
+ " + General Tasks:",
+ " |- ActiveThreads: " + _generalThreadPool.getActiveCount(),
+ " |- getCorePoolSize: " + _generalThreadPool.getCorePoolSize(),
+ " |- MaximumPoolSize: " + _generalThreadPool.getMaximumPoolSize(),
+ " |- LargestPoolSize: " + _generalThreadPool.getLargestPoolSize(),
+ " |- PoolSize: " + _generalThreadPool.getPoolSize(),
+ " |- CompletedTasks: " + _generalThreadPool.getCompletedTaskCount(),
+ " |- QueuedTasks: " + _generalThreadPool.getQueue().size(),
+ " | -------",
+ " + Javolution stats:",
+ " |- FastList: " + FastList.report(),
+ " |- FastMap: " + FastMap.report(),
+ " |- FastSet: " + FastSet.report(),
+ " | -------"
+ };
+ }
+
+ private static class PriorityThreadFactory implements ThreadFactory
+ {
+ private final int _prio;
+ private final String _name;
+ private final AtomicInteger _threadNumber = new AtomicInteger(1);
+ private final ThreadGroup _group;
+
+ public PriorityThreadFactory(String name, int prio)
+ {
+ _prio = prio;
+ _name = name;
+ _group = new ThreadGroup(_name);
+ }
+
+ @Override
+ public Thread newThread(Runnable r)
+ {
+ Thread t = new Thread(_group, r);
+ t.setName(_name + "-" + _threadNumber.getAndIncrement());
+ t.setPriority(_prio);
+ return t;
+ }
+
+ public ThreadGroup getGroup()
+ {
+ return _group;
+ }
+ }
+
+ public void shutdown()
+ {
+ _shutdown = true;
+ try
+ {
+ _effectsScheduledThreadPool.awaitTermination(1, TimeUnit.SECONDS);
+ _generalScheduledThreadPool.awaitTermination(1, TimeUnit.SECONDS);
+ _generalPacketsThreadPool.awaitTermination(1, TimeUnit.SECONDS);
+ _ioPacketsThreadPool.awaitTermination(1, TimeUnit.SECONDS);
+ _generalThreadPool.awaitTermination(1, TimeUnit.SECONDS);
+ _effectsScheduledThreadPool.shutdown();
+ _generalScheduledThreadPool.shutdown();
+ _generalPacketsThreadPool.shutdown();
+ _ioPacketsThreadPool.shutdown();
+ _generalThreadPool.shutdown();
+ _log.info("All ThreadPools are now stopped");
+
+ }
+ catch (InterruptedException e)
+ {
+ _log.log(Level.WARNING, "", e);
+ }
+ }
+
+ public boolean isShutdown()
+ {
+ return _shutdown;
+ }
+
+ public void purge()
+ {
+ _effectsScheduledThreadPool.purge();
+ _generalScheduledThreadPool.purge();
+ _aiScheduledThreadPool.purge();
+ _ioPacketsThreadPool.purge();
+ _generalPacketsThreadPool.purge();
+ _generalThreadPool.purge();
+ }
+
+ public String getPacketStats()
+ {
+ final StringBuilder sb = new StringBuilder(1000);
+ ThreadFactory tf = _generalPacketsThreadPool.getThreadFactory();
+ if (tf instanceof PriorityThreadFactory)
+ {
+ PriorityThreadFactory ptf = (PriorityThreadFactory) tf;
+ int count = ptf.getGroup().activeCount();
+ Thread[] threads = new Thread[count + 2];
+ ptf.getGroup().enumerate(threads);
+ StringUtil.append(sb, "General Packet Thread Pool:\r\n" + "Tasks in the queue: ", String.valueOf(_generalPacketsThreadPool.getQueue().size()), "\r\n" + "Showing threads stack trace:\r\n" + "There should be ", String.valueOf(count), " Threads\r\n");
+ for (Thread t : threads)
+ {
+ if (t == null)
+ {
+ continue;
+ }
+
+ StringUtil.append(sb, t.getName(), "\r\n");
+ for (StackTraceElement ste : t.getStackTrace())
+ {
+ StringUtil.append(sb, ste.toString(), "\r\n");
+ }
+ }
+ }
+
+ sb.append("Packet Tp stack traces printed.\r\n");
+
+ return sb.toString();
+ }
+
+ public String getIOPacketStats()
+ {
+ final StringBuilder sb = new StringBuilder(1000);
+ ThreadFactory tf = _ioPacketsThreadPool.getThreadFactory();
+
+ if (tf instanceof PriorityThreadFactory)
+ {
+ PriorityThreadFactory ptf = (PriorityThreadFactory) tf;
+ int count = ptf.getGroup().activeCount();
+ Thread[] threads = new Thread[count + 2];
+ ptf.getGroup().enumerate(threads);
+ StringUtil.append(sb, "I/O Packet Thread Pool:\r\n" + "Tasks in the queue: ", String.valueOf(_ioPacketsThreadPool.getQueue().size()), "\r\n" + "Showing threads stack trace:\r\n" + "There should be ", String.valueOf(count), " Threads\r\n");
+
+ for (Thread t : threads)
+ {
+ if (t == null)
+ {
+ continue;
+ }
+
+ StringUtil.append(sb, t.getName(), "\r\n");
+
+ for (StackTraceElement ste : t.getStackTrace())
+ {
+ StringUtil.append(sb, ste.toString(), "\r\n");
+ }
+ }
+ }
+
+ sb.append("Packet Tp stack traces printed.\r\n");
+
+ return sb.toString();
+ }
+
+ public String getGeneralStats()
+ {
+ final StringBuilder sb = new StringBuilder(1000);
+ ThreadFactory tf = _generalThreadPool.getThreadFactory();
+
+ if (tf instanceof PriorityThreadFactory)
+ {
+ PriorityThreadFactory ptf = (PriorityThreadFactory) tf;
+ int count = ptf.getGroup().activeCount();
+ Thread[] threads = new Thread[count + 2];
+ ptf.getGroup().enumerate(threads);
+ StringUtil.append(sb, "General Thread Pool:\r\n" + "Tasks in the queue: ", String.valueOf(_generalThreadPool.getQueue().size()), "\r\n" + "Showing threads stack trace:\r\n" + "There should be ", String.valueOf(count), " Threads\r\n");
+
+ for (Thread t : threads)
+ {
+ if (t == null)
+ {
+ continue;
+ }
+
+ StringUtil.append(sb, t.getName(), "\r\n");
+
+ for (StackTraceElement ste : t.getStackTrace())
+ {
+ StringUtil.append(sb, ste.toString(), "\r\n");
+ }
+ }
+ }
+
+ sb.append("Packet Tp stack traces printed.\r\n");
+
+ return sb.toString();
+ }
+
+ protected class PurgeTask implements Runnable
+ {
+ @Override
+ public void run()
+ {
+ _effectsScheduledThreadPool.purge();
+ _generalScheduledThreadPool.purge();
+ _aiScheduledThreadPool.purge();
+ }
+ }
+
+ @SuppressWarnings("synthetic-access")
+ private static class SingletonHolder
+ {
+ protected static final ThreadPoolManager _instance = new ThreadPoolManager();
+ }
+}
\ No newline at end of file
diff --git a/L2J_Server/java/com/l2jserver/gameserver/TradeController.java b/L2J_Server/java/com/l2jserver/gameserver/TradeController.java
new file mode 100644
index 00000000..0507ec5c
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/TradeController.java
@@ -0,0 +1,330 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javolution.util.FastList;
+import javolution.util.FastMap;
+
+import com.l2jserver.Config;
+import com.l2jserver.L2DatabaseFactory;
+import com.l2jserver.gameserver.datatables.ItemTable;
+import com.l2jserver.gameserver.model.L2TradeList;
+import com.l2jserver.gameserver.model.L2TradeList.L2TradeItem;
+
+/**
+ * This class ...
+ * @version $Revision: 1.5.4.13 $ $Date: 2005/04/06 16:13:38 $
+ */
+public class TradeController
+{
+ private static Logger _log = Logger.getLogger(TradeController.class.getName());
+
+ private int _nextListId;
+ private final Map _lists = new FastMap<>();
+
+ /** Task launching the function for restore count of Item (Clan Hall) */
+ /*
+ * public class RestoreCount implements Runnable { private int _timer; public RestoreCount(int time) { _timer = time; } public void run() { restoreCount(_timer); dataTimerSave(_timer); ThreadPoolManager.getInstance().scheduleGeneral(new RestoreCount(_timer), (long)_timer*60*60*1000); } }
+ */
+
+ public static TradeController getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ private TradeController()
+ {
+ _lists.clear();
+ Connection con = null;
+
+ /*
+ * Initialize Shop buylist
+ */
+ try
+ {
+ con = L2DatabaseFactory.getInstance().getConnection();
+ PreparedStatement statement1 = con.prepareStatement("SELECT shop_id, npc_id FROM merchant_shopids");
+ ResultSet rset1 = statement1.executeQuery();
+
+ int itemId, price, maxCount, currentCount, time;
+ long saveTimer;
+ PreparedStatement statement = con.prepareStatement("SELECT item_id, price, shop_id, " + L2DatabaseFactory.getInstance().safetyString("order") + ", count, currentCount, time, savetimer FROM merchant_buylists WHERE shop_id=? ORDER BY " + L2DatabaseFactory.getInstance().safetyString("order") + " ASC");
+ while (rset1.next())
+ {
+ statement.setString(1, String.valueOf(rset1.getInt("shop_id")));
+ ResultSet rset = statement.executeQuery();
+ statement.clearParameters();
+
+ int shopId = rset1.getInt("shop_id");
+ L2TradeList buy1 = new L2TradeList(shopId);
+
+ while (rset.next())
+ {
+ itemId = rset.getInt("item_id");
+ price = rset.getInt("price");
+ maxCount = rset.getInt("count");
+ currentCount = rset.getInt("currentCount");
+ time = rset.getInt("time");
+ saveTimer = rset.getLong("saveTimer");
+
+ L2TradeItem item = new L2TradeItem(shopId, itemId);
+ if (ItemTable.getInstance().getTemplate(itemId) == null)
+ {
+ _log.warning("Skipping itemId: " + itemId + " on buylistId: " + buy1.getListId() + ", missing data for that item.");
+ continue;
+ }
+
+ if (price <= -1)
+ {
+ price = ItemTable.getInstance().getTemplate(itemId).getReferencePrice();
+ }
+
+ if (Config.DEBUG)
+ {
+ // debug
+ double diff = ((double) (price)) / ItemTable.getInstance().getTemplate(itemId).getReferencePrice();
+ if ((diff < 0.8) || (diff > 1.2))
+ {
+ _log.severe("PRICING DEBUG: TradeListId: " + buy1.getListId() + " - ItemId: " + itemId + " (" + ItemTable.getInstance().getTemplate(itemId).getName() + ") diff: " + diff + " - Price: " + price + " - Reference: " + ItemTable.getInstance().getTemplate(itemId).getReferencePrice());
+ }
+ }
+
+ item.setPrice(price);
+
+ item.setRestoreDelay(time);
+ item.setNextRestoreTime(saveTimer);
+ item.setMaxCount(maxCount);
+
+ if (currentCount > -1)
+ {
+ item.setCurrentCount(currentCount);
+ }
+ else
+ {
+ item.setCurrentCount(maxCount);
+ }
+
+ buy1.addItem(item);
+ }
+
+ buy1.setNpcId(rset1.getString("npc_id"));
+ _lists.put(buy1.getListId(), buy1);
+ _nextListId = Math.max(_nextListId, buy1.getListId() + 1);
+
+ rset.close();
+ }
+ statement.close();
+ rset1.close();
+ statement1.close();
+
+ _log.info("TradeController: Loaded " + _lists.size() + " Buylists.");
+ }
+ catch (Exception e)
+ {
+ // problem with initializing spawn, go to next one
+ _log.log(Level.WARNING, "TradeController: Buylists could not be initialized: " + e.getMessage(), e);
+ }
+ finally
+ {
+ L2DatabaseFactory.close(con);
+ }
+
+ /*
+ * If enabled, initialize the custom buylist
+ */
+ if (Config.CUSTOM_MERCHANT_TABLES)
+ {
+ try
+ {
+ int initialSize = _lists.size();
+ con = L2DatabaseFactory.getInstance().getConnection();
+ PreparedStatement statement1 = con.prepareStatement("SELECT shop_id, npc_id FROM custom_merchant_shopids");
+ ResultSet rset1 = statement1.executeQuery();
+
+ int itemId, price, maxCount, currentCount, time;
+ long saveTimer;
+ PreparedStatement statement = con.prepareStatement("SELECT item_id, price, shop_id, " + L2DatabaseFactory.getInstance().safetyString("order") + ", count, currentCount, time, savetimer FROM custom_merchant_buylists WHERE shop_id=? ORDER BY " + L2DatabaseFactory.getInstance().safetyString("order") + " ASC");
+ while (rset1.next())
+ {
+ statement.setString(1, String.valueOf(rset1.getInt("shop_id")));
+ ResultSet rset = statement.executeQuery();
+ statement.clearParameters();
+
+ int shopId = rset1.getInt("shop_id");
+ L2TradeList buy1 = new L2TradeList(shopId);
+
+ while (rset.next())
+ {
+ itemId = rset.getInt("item_id");
+ price = rset.getInt("price");
+ maxCount = rset.getInt("count");
+ currentCount = rset.getInt("currentCount");
+ time = rset.getInt("time");
+ saveTimer = rset.getLong("saveTimer");
+
+ L2TradeItem item = new L2TradeItem(shopId, itemId);
+ if (ItemTable.getInstance().getTemplate(itemId) == null)
+ {
+ _log.warning("Skipping itemId: " + itemId + " on buylistId: " + buy1.getListId() + ", missing data for that item.");
+ continue;
+ }
+
+ if (price <= -1)
+ {
+ price = ItemTable.getInstance().getTemplate(itemId).getReferencePrice();
+ }
+
+ if (Config.DEBUG)
+ {
+ // debug
+ double diff = ((double) (price)) / ItemTable.getInstance().getTemplate(itemId).getReferencePrice();
+ if ((diff < 0.8) || (diff > 1.2))
+ {
+ _log.severe("PRICING DEBUG: TradeListId: " + buy1.getListId() + " - ItemId: " + itemId + " (" + ItemTable.getInstance().getTemplate(itemId).getName() + ") diff: " + diff + " - Price: " + price + " - Reference: " + ItemTable.getInstance().getTemplate(itemId).getReferencePrice());
+ }
+ }
+
+ item.setPrice(price);
+
+ item.setRestoreDelay(time);
+ item.setNextRestoreTime(saveTimer);
+ item.setMaxCount(maxCount);
+
+ if (currentCount > -1)
+ {
+ item.setCurrentCount(currentCount);
+ }
+ else
+ {
+ item.setCurrentCount(maxCount);
+ }
+
+ buy1.addItem(item);
+ }
+
+ buy1.setNpcId(rset1.getString("npc_id"));
+ _lists.put(buy1.getListId(), buy1);
+ _nextListId = Math.max(_nextListId, buy1.getListId() + 1);
+
+ rset.close();
+ }
+ statement.close();
+ rset1.close();
+ statement1.close();
+
+ _log.info("TradeController: Loaded " + (_lists.size() - initialSize) + " Custom Buylists.");
+
+ }
+ catch (Exception e)
+ {
+ // problem with initializing spawn, go to next one
+ _log.log(Level.WARNING, "TradeController: Buylists could not be initialized: " + e.getMessage(), e);
+ }
+ finally
+ {
+ L2DatabaseFactory.close(con);
+ }
+ }
+ }
+
+ public L2TradeList getBuyList(int listId)
+ {
+ return _lists.get(listId);
+ }
+
+ public List getBuyListByNpcId(int npcId)
+ {
+ List lists = new FastList<>();
+ Collection values = _lists.values();
+
+ for (L2TradeList list : values)
+ {
+ String tradeNpcId = list.getNpcId();
+ if (tradeNpcId.startsWith("gm"))
+ {
+ continue;
+ }
+ if (npcId == Integer.parseInt(tradeNpcId))
+ {
+ lists.add(list);
+ }
+ }
+ return lists;
+ }
+
+ public void dataCountStore()
+ {
+ Connection con = null;
+ int listId;
+
+ try
+ {
+ con = L2DatabaseFactory.getInstance().getConnection();
+ PreparedStatement statement = con.prepareStatement("UPDATE merchant_buylists SET currentCount=? WHERE item_id=? AND shop_id=?");
+ for (L2TradeList list : _lists.values())
+ {
+ if (list.hasLimitedStockItem())
+ {
+ listId = list.getListId();
+
+ for (L2TradeItem item : list.getItems())
+ {
+ long currentCount;
+ if (item.hasLimitedStock() && ((currentCount = item.getCurrentCount()) < item.getMaxCount()))
+ {
+ statement.setLong(1, currentCount);
+ statement.setInt(2, item.getItemId());
+ statement.setInt(3, listId);
+ statement.executeUpdate();
+ statement.clearParameters();
+ }
+ }
+ }
+ }
+ statement.close();
+ }
+ catch (Exception e)
+ {
+ _log.log(Level.SEVERE, "TradeController: Could not store Count Item: " + e.getMessage(), e);
+ }
+ finally
+ {
+ L2DatabaseFactory.close(con);
+ }
+ }
+
+ /**
+ * @return
+ */
+ public synchronized int getNextId()
+ {
+ return _nextListId++;
+ }
+
+ @SuppressWarnings("synthetic-access")
+ private static class SingletonHolder
+ {
+ protected static final TradeController _instance = new TradeController();
+ }
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/ai/AbstractAI.java b/L2J_Server/java/com/l2jserver/gameserver/ai/AbstractAI.java
new file mode 100644
index 00000000..fbc2c8fc
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/ai/AbstractAI.java
@@ -0,0 +1,896 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.ai;
+
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
+
+import java.util.concurrent.Future;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.l2jserver.gameserver.GameTimeController;
+import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.model.L2CharPosition;
+import com.l2jserver.gameserver.model.L2Object;
+import com.l2jserver.gameserver.model.L2Skill;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.actor.L2Summon;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
+import com.l2jserver.gameserver.network.serverpackets.AutoAttackStart;
+import com.l2jserver.gameserver.network.serverpackets.AutoAttackStop;
+import com.l2jserver.gameserver.network.serverpackets.Die;
+import com.l2jserver.gameserver.network.serverpackets.MoveToLocation;
+import com.l2jserver.gameserver.network.serverpackets.MoveToPawn;
+import com.l2jserver.gameserver.network.serverpackets.StopMove;
+import com.l2jserver.gameserver.network.serverpackets.StopRotation;
+import com.l2jserver.gameserver.taskmanager.AttackStanceTaskManager;
+
+/**
+ * Mother class of all objects AI in the world.
+ *
+ * AbastractAI :
+ *
+ *
L2CharacterAI
+ *
+ */
+abstract class AbstractAI implements Ctrl
+{
+ protected static final Logger _log = Logger.getLogger(AbstractAI.class.getName());
+
+ class FollowTask implements Runnable
+ {
+ protected int _range = 70;
+
+ public FollowTask()
+ {
+ }
+
+ public FollowTask(int range)
+ {
+ _range = range;
+ }
+
+ @Override
+ public void run()
+ {
+ try
+ {
+ if (_followTask == null)
+ {
+ return;
+ }
+
+ L2Character followTarget = _followTarget; // copy to prevent NPE
+ if (followTarget == null)
+ {
+ if (_actor instanceof L2Summon)
+ {
+ ((L2Summon) _actor).setFollowStatus(false);
+ }
+ setIntention(AI_INTENTION_IDLE);
+ return;
+ }
+
+ if (!_actor.isInsideRadius(followTarget, _range, true, false))
+ {
+ if (!_actor.isInsideRadius(followTarget, 3000, true, false))
+ {
+ // if the target is too far (maybe also teleported)
+ if (_actor instanceof L2Summon)
+ {
+ ((L2Summon) _actor).setFollowStatus(false);
+ }
+
+ setIntention(AI_INTENTION_IDLE);
+ return;
+ }
+
+ moveToPawn(followTarget, _range);
+ }
+ }
+ catch (Exception e)
+ {
+ _log.log(Level.WARNING, "", e);
+ }
+ }
+ }
+
+ /** The character that this AI manages */
+ protected final L2Character _actor;
+
+ /** An accessor for private methods of the actor */
+ protected final L2Character.AIAccessor _accessor;
+
+ /** Current long-term intention */
+ protected CtrlIntention _intention = AI_INTENTION_IDLE;
+ /** Current long-term intention parameter */
+ protected Object _intentionArg0 = null;
+ /** Current long-term intention parameter */
+ protected Object _intentionArg1 = null;
+
+ /** Flags about client's state, in order to know which messages to send */
+ protected volatile boolean _clientMoving;
+ /** Flags about client's state, in order to know which messages to send */
+ protected volatile boolean _clientAutoAttacking;
+ /** Flags about client's state, in order to know which messages to send */
+ protected int _clientMovingToPawnOffset;
+
+ /** Different targets this AI maintains */
+ private L2Object _target;
+ private L2Character _castTarget;
+ protected L2Character _attackTarget;
+ protected L2Character _followTarget;
+
+ /** The skill we are currently casting by INTENTION_CAST */
+ L2Skill _skill;
+
+ /** Different internal state flags */
+ private int _moveToPawnTimeout;
+
+ protected Future> _followTask = null;
+ private static final int FOLLOW_INTERVAL = 1000;
+ private static final int ATTACK_FOLLOW_INTERVAL = 500;
+
+ /**
+ * Constructor of AbstractAI.
+ *
+ * @param accessor The AI accessor of the L2Character
+ */
+ protected AbstractAI(L2Character.AIAccessor accessor)
+ {
+ _accessor = accessor;
+
+ // Get the L2Character managed by this Accessor AI
+ _actor = accessor.getActor();
+ }
+
+ /**
+ * Return the L2Character managed by this Accessor AI.
+ *
+ */
+ @Override
+ public L2Character getActor()
+ {
+ return _actor;
+ }
+
+ /**
+ * Return the current Intention.
+ *
+ */
+ @Override
+ public CtrlIntention getIntention()
+ {
+ return _intention;
+ }
+
+ protected void setCastTarget(L2Character target)
+ {
+ _castTarget = target;
+ }
+
+ /**
+ * Return the current cast target.
+ *
+ */
+ public L2Character getCastTarget()
+ {
+ return _castTarget;
+ }
+
+ protected void setAttackTarget(L2Character target)
+ {
+ _attackTarget = target;
+ }
+
+ /**
+ * Return current attack target.
+ *
+ */
+ @Override
+ public L2Character getAttackTarget()
+ {
+ return _attackTarget;
+ }
+
+ /**
+ * Set the Intention of this AbstractAI.
+ *
+ * Caution : This method is USED by AI classes
+ *
+ * Overridden in :
+ * L2AttackableAI : Create an AI Task executed every 1s (if necessary)
+ * L2PlayerAI : Stores the current AI intention parameters to later restore it if necessary
+ *
+ * @param intention The new Intention to set to the AI
+ * @param arg0 The first parameter of the Intention
+ * @param arg1 The second parameter of the Intention
+ */
+ synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
+ {
+ /*
+ * if (Config.DEBUG) _log.warning("AbstractAI: changeIntention -> " + intention + " " + arg0 + " " + arg1);
+ */
+
+ _intention = intention;
+ _intentionArg0 = arg0;
+ _intentionArg1 = arg1;
+ }
+
+ /**
+ * Launch the L2CharacterAI onIntention method corresponding to the new Intention.
+ *
+ * Caution : Stop the FOLLOW mode if necessary
+ *
+ * @param intention The new Intention to set to the AI
+ */
+ @Override
+ public final void setIntention(CtrlIntention intention)
+ {
+ setIntention(intention, null, null);
+ }
+
+ /**
+ * Launch the L2CharacterAI onIntention method corresponding to the new Intention.
+ *
+ * Caution : Stop the FOLLOW mode if necessary
+ *
+ * @param intention The new Intention to set to the AI
+ * @param arg0 The first parameter of the Intention (optional target)
+ */
+ @Override
+ public final void setIntention(CtrlIntention intention, Object arg0)
+ {
+ setIntention(intention, arg0, null);
+ }
+
+ /**
+ * Launch the L2CharacterAI onIntention method corresponding to the new Intention.
+ *
+ * Caution : Stop the FOLLOW mode if necessary
+ *
+ * @param intention The new Intention to set to the AI
+ * @param arg0 The first parameter of the Intention (optional target)
+ * @param arg1 The second parameter of the Intention (optional target)
+ */
+ /*
+ * public final void informAIIntention(CtrlIntention intent, Object arg0) { ThreadPoolManager.getInstance().executeAi(new InformAIMsg(this, intent, arg0)); } public final void informAIIntention(CtrlIntention intent) { ThreadPoolManager.getInstance().executeAi(new InformAIMsg(this, intent,
+ * null)); } public class InformAIMsg implements Runnable { private AbstractAI _ai; private CtrlIntention _intent; private Object _arg0; public InformAIMsg(AbstractAI ai, CtrlIntention intention, Object arg0) { _ai=ai; _intent = intention; _arg0 = arg0; } public final void run() {
+ * _ai.setIntention(_intent, _arg0, null); } }
+ */
+ @Override
+ public final void setIntention(CtrlIntention intention, Object arg0, Object arg1)
+ {
+ /*
+ * if (Config.DEBUG) _log.warning("AbstractAI: setIntention -> " + intention + " " + arg0 + " " + arg1);
+ */
+
+ // Stop the follow mode if necessary
+ if ((intention != AI_INTENTION_FOLLOW) && (intention != AI_INTENTION_ATTACK))
+ {
+ stopFollow();
+ }
+
+ // Launch the onIntention method of the L2CharacterAI corresponding to the new Intention
+ switch (intention)
+ {
+ case AI_INTENTION_IDLE:
+ onIntentionIdle();
+ break;
+ case AI_INTENTION_ACTIVE:
+ onIntentionActive();
+ break;
+ case AI_INTENTION_REST:
+ onIntentionRest();
+ break;
+ case AI_INTENTION_ATTACK:
+ onIntentionAttack((L2Character) arg0);
+ break;
+ case AI_INTENTION_CAST:
+ onIntentionCast((L2Skill) arg0, (L2Object) arg1);
+ break;
+ case AI_INTENTION_MOVE_TO:
+ onIntentionMoveTo((L2CharPosition) arg0);
+ break;
+ case AI_INTENTION_FOLLOW:
+ onIntentionFollow((L2Character) arg0);
+ break;
+ case AI_INTENTION_PICK_UP:
+ onIntentionPickUp((L2Object) arg0);
+ break;
+ case AI_INTENTION_INTERACT:
+ onIntentionInteract((L2Object) arg0);
+ break;
+ }
+ }
+
+ /**
+ * Launch the L2CharacterAI onEvt method corresponding to the Event.
+ *
+ * Caution : The current general intention won't be change (ex : If the character attack and is stunned, he will attack again after the stunned period)
+ *
+ * @param evt The event whose the AI must be notified
+ */
+ @Override
+ public final void notifyEvent(CtrlEvent evt)
+ {
+ notifyEvent(evt, null, null);
+ }
+
+ /**
+ * Launch the L2CharacterAI onEvt method corresponding to the Event.
+ *
+ * Caution : The current general intention won't be change (ex : If the character attack and is stunned, he will attack again after the stunned period)
+ *
+ * @param evt The event whose the AI must be notified
+ * @param arg0 The first parameter of the Event (optional target)
+ */
+ @Override
+ public final void notifyEvent(CtrlEvent evt, Object arg0)
+ {
+ notifyEvent(evt, arg0, null);
+ }
+
+ /*
+ * public final void informAIEvent(CtrlEvent evt) { ThreadPoolManager.getInstance().executeAi(new InformAIEvent(this, evt, null, null)); } public final void informAIEvent(CtrlEvent evt, Object arg0) { ThreadPoolManager.getInstance().executeAi(new InformAIEvent(this, evt, arg0, null)); } public
+ * final void informAIEvent(CtrlEvent evt, Object arg0, Object arg1) { ThreadPoolManager.getInstance().executeAi(new InformAIEvent(this, evt, arg0, arg1)); } public class InformAIEvent implements Runnable { private AbstractAI _ai; private CtrlEvent _evt; private Object _arg0, _arg1; public
+ * InformAIEvent(AbstractAI ai, CtrlEvent evt, Object arg0, Object arg1) { _ai=ai; _evt = evt; _arg0 = arg0; _arg1 = arg1; } public final void run() { _ai.notifyEvent(_evt, _arg0, _arg1); } }
+ */
+ /**
+ * Launch the L2CharacterAI onEvt method corresponding to the Event.
+ *
+ * Caution : The current general intention won't be change (ex : If the character attack and is stunned, he will attack again after the stunned period)
+ *
+ * @param evt The event whose the AI must be notified
+ * @param arg0 The first parameter of the Event (optional target)
+ * @param arg1 The second parameter of the Event (optional target)
+ */
+ @Override
+ public final void notifyEvent(CtrlEvent evt, Object arg0, Object arg1)
+ {
+ if ((!_actor.isVisible() && !_actor.isTeleporting()) || !_actor.hasAI())
+ {
+ return;
+ }
+
+ /*
+ * if (Config.DEBUG) _log.warning("AbstractAI: notifyEvent -> " + evt + " " + arg0 + " " + arg1);
+ */
+
+ switch (evt)
+ {
+ case EVT_THINK:
+ onEvtThink();
+ break;
+ case EVT_ATTACKED:
+ onEvtAttacked((L2Character) arg0);
+ break;
+ case EVT_AGGRESSION:
+ onEvtAggression((L2Character) arg0, ((Number) arg1).intValue());
+ break;
+ case EVT_STUNNED:
+ onEvtStunned((L2Character) arg0);
+ break;
+ case EVT_PARALYZED:
+ onEvtParalyzed((L2Character) arg0);
+ break;
+ case EVT_SLEEPING:
+ onEvtSleeping((L2Character) arg0);
+ break;
+ case EVT_ROOTED:
+ onEvtRooted((L2Character) arg0);
+ break;
+ case EVT_CONFUSED:
+ onEvtConfused((L2Character) arg0);
+ break;
+ case EVT_MUTED:
+ onEvtMuted((L2Character) arg0);
+ break;
+ case EVT_EVADED:
+ onEvtEvaded((L2Character) arg0);
+ break;
+ case EVT_READY_TO_ACT:
+ if (!_actor.isCastingNow() && !_actor.isCastingSimultaneouslyNow())
+ {
+ onEvtReadyToAct();
+ }
+ break;
+ case EVT_USER_CMD:
+ onEvtUserCmd(arg0, arg1);
+ break;
+ case EVT_ARRIVED:
+ // happens e.g. from stopmove but we don't process it if we're casting
+ if (!_actor.isCastingNow() && !_actor.isCastingSimultaneouslyNow())
+ {
+ onEvtArrived();
+ }
+ break;
+ case EVT_ARRIVED_REVALIDATE:
+ // this is disregarded if the char is not moving any more
+ if (_actor.isMoving())
+ {
+ onEvtArrivedRevalidate();
+ }
+ break;
+ case EVT_ARRIVED_BLOCKED:
+ onEvtArrivedBlocked((L2CharPosition) arg0);
+ break;
+ case EVT_FORGET_OBJECT:
+ onEvtForgetObject((L2Object) arg0);
+ break;
+ case EVT_CANCEL:
+ onEvtCancel();
+ break;
+ case EVT_DEAD:
+ onEvtDead();
+ break;
+ case EVT_FAKE_DEATH:
+ onEvtFakeDeath();
+ break;
+ case EVT_FINISH_CASTING:
+ onEvtFinishCasting();
+ break;
+ }
+ }
+
+ protected abstract void onIntentionIdle();
+
+ protected abstract void onIntentionActive();
+
+ protected abstract void onIntentionRest();
+
+ protected abstract void onIntentionAttack(L2Character target);
+
+ protected abstract void onIntentionCast(L2Skill skill, L2Object target);
+
+ protected abstract void onIntentionMoveTo(L2CharPosition destination);
+
+ protected abstract void onIntentionFollow(L2Character target);
+
+ protected abstract void onIntentionPickUp(L2Object item);
+
+ protected abstract void onIntentionInteract(L2Object object);
+
+ protected abstract void onEvtThink();
+
+ protected abstract void onEvtAttacked(L2Character attacker);
+
+ protected abstract void onEvtAggression(L2Character target, int aggro);
+
+ protected abstract void onEvtStunned(L2Character attacker);
+
+ protected abstract void onEvtParalyzed(L2Character attacker);
+
+ protected abstract void onEvtSleeping(L2Character attacker);
+
+ protected abstract void onEvtRooted(L2Character attacker);
+
+ protected abstract void onEvtConfused(L2Character attacker);
+
+ protected abstract void onEvtMuted(L2Character attacker);
+
+ protected abstract void onEvtEvaded(L2Character attacker);
+
+ protected abstract void onEvtReadyToAct();
+
+ protected abstract void onEvtUserCmd(Object arg0, Object arg1);
+
+ protected abstract void onEvtArrived();
+
+ protected abstract void onEvtArrivedRevalidate();
+
+ protected abstract void onEvtArrivedBlocked(L2CharPosition blocked_at_pos);
+
+ protected abstract void onEvtForgetObject(L2Object object);
+
+ protected abstract void onEvtCancel();
+
+ protected abstract void onEvtDead();
+
+ protected abstract void onEvtFakeDeath();
+
+ protected abstract void onEvtFinishCasting();
+
+ /**
+ * Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor.
+ *
+ * Caution : Low level function, used by AI subclasses
+ *
+ */
+ protected void clientActionFailed()
+ {
+ if (_actor instanceof L2PcInstance)
+ {
+ _actor.sendPacket(ActionFailed.STATIC_PACKET);
+ }
+ }
+
+ /**
+ * Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn (broadcast).
+ *
+ * Caution : Low level function, used by AI subclasses
+ *
+ */
+ protected void moveToPawn(L2Object pawn, int offset)
+ {
+ // Check if actor can move
+ if (!_actor.isMovementDisabled())
+ {
+ if (offset < 10)
+ {
+ offset = 10;
+ }
+
+ // prevent possible extra calls to this function (there is none?),
+ // also don't send movetopawn packets too often
+ boolean sendPacket = true;
+ if (_clientMoving && (_target == pawn))
+ {
+ if (_clientMovingToPawnOffset == offset)
+ {
+ if (GameTimeController.getGameTicks() < _moveToPawnTimeout)
+ {
+ return;
+ }
+ sendPacket = false;
+ }
+ else if (_actor.isOnGeodataPath())
+ {
+ // minimum time to calculate new route is 2 seconds
+ if (GameTimeController.getGameTicks() < (_moveToPawnTimeout + 10))
+ {
+ return;
+ }
+ }
+ }
+
+ // Set AI movement data
+ _clientMoving = true;
+ _clientMovingToPawnOffset = offset;
+ _target = pawn;
+ _moveToPawnTimeout = GameTimeController.getGameTicks();
+ _moveToPawnTimeout += 1000 / GameTimeController.MILLIS_IN_TICK;
+
+ if ((pawn == null) || (_accessor == null))
+ {
+ return;
+ }
+
+ // Calculate movement data for a move to location action and add the actor to movingObjects of GameTimeController
+ _accessor.moveTo(pawn.getX(), pawn.getY(), pawn.getZ(), offset);
+
+ if (!_actor.isMoving())
+ {
+ _actor.sendPacket(ActionFailed.STATIC_PACKET);
+ return;
+ }
+
+ // Send a Server->Client packet MoveToPawn/CharMoveToLocation to the actor and all L2PcInstance in its _knownPlayers
+ if (pawn instanceof L2Character)
+ {
+ if (_actor.isOnGeodataPath())
+ {
+ _actor.broadcastPacket(new MoveToLocation(_actor));
+ _clientMovingToPawnOffset = 0;
+ }
+ else if (sendPacket)
+ {
+ _actor.broadcastPacket(new MoveToPawn(_actor, (L2Character) pawn, offset));
+ }
+ }
+ else
+ {
+ _actor.broadcastPacket(new MoveToLocation(_actor));
+ }
+ }
+ else
+ {
+ _actor.sendPacket(ActionFailed.STATIC_PACKET);
+ }
+ }
+
+ /**
+ * Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast).
+ *
+ * Caution : Low level function, used by AI subclasses
+ *
+ */
+ protected void moveTo(int x, int y, int z)
+ {
+ // Chek if actor can move
+ if (!_actor.isMovementDisabled())
+ {
+ // Set AI movement data
+ _clientMoving = true;
+ _clientMovingToPawnOffset = 0;
+
+ // Calculate movement data for a move to location action and add the actor to movingObjects of GameTimeController
+ _accessor.moveTo(x, y, z);
+
+ // Send a Server->Client packet CharMoveToLocation to the actor and all L2PcInstance in its _knownPlayers
+ MoveToLocation msg = new MoveToLocation(_actor);
+ _actor.broadcastPacket(msg);
+
+ }
+ else
+ {
+ _actor.sendPacket(ActionFailed.STATIC_PACKET);
+ }
+ }
+
+ /**
+ * Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast).
+ *
+ * Caution : Low level function, used by AI subclasses
+ *
+ */
+ protected void clientStopMoving(L2CharPosition pos)
+ {
+ /*
+ * if (Config.DEBUG) _log.warning("clientStopMoving();");
+ */
+
+ // Stop movement of the L2Character
+ if (_actor.isMoving())
+ {
+ _accessor.stopMove(pos);
+ }
+
+ _clientMovingToPawnOffset = 0;
+
+ if (_clientMoving || (pos != null))
+ {
+ _clientMoving = false;
+
+ // Send a Server->Client packet StopMove to the actor and all L2PcInstance in its _knownPlayers
+ StopMove msg = new StopMove(_actor);
+ _actor.broadcastPacket(msg);
+
+ if (pos != null)
+ {
+ // Send a Server->Client packet StopRotation to the actor and all L2PcInstance in its _knownPlayers
+ StopRotation sr = new StopRotation(_actor.getObjectId(), pos.heading, 0);
+ _actor.sendPacket(sr);
+ _actor.broadcastPacket(sr);
+ }
+ }
+ }
+
+ // Client has already arrived to target, no need to force StopMove packet
+ protected void clientStoppedMoving()
+ {
+ if (_clientMovingToPawnOffset > 0) // movetoPawn needs to be stopped
+ {
+ _clientMovingToPawnOffset = 0;
+ StopMove msg = new StopMove(_actor);
+ _actor.broadcastPacket(msg);
+ }
+ _clientMoving = false;
+ }
+
+ public boolean isAutoAttacking()
+ {
+ return _clientAutoAttacking;
+ }
+
+ public void setAutoAttacking(boolean isAutoAttacking)
+ {
+ if (_actor instanceof L2Summon)
+ {
+ L2Summon summon = (L2Summon) _actor;
+ if (summon.getOwner() != null)
+ {
+ summon.getOwner().getAI().setAutoAttacking(isAutoAttacking);
+ }
+ return;
+ }
+ _clientAutoAttacking = isAutoAttacking;
+ }
+
+ /**
+ * Start the actor Auto Attack client side by sending Server->Client packet AutoAttackStart (broadcast).
+ *
+ * Caution : Low level function, used by AI subclasses
+ *
+ */
+ public void clientStartAutoAttack()
+ {
+ if (_actor instanceof L2Summon)
+ {
+ L2Summon summon = (L2Summon) _actor;
+ if (summon.getOwner() != null)
+ {
+ summon.getOwner().getAI().clientStartAutoAttack();
+ }
+ return;
+ }
+ if (!isAutoAttacking())
+ {
+ if ((_actor instanceof L2PcInstance) && (((L2PcInstance) _actor).getPet() != null))
+ {
+ ((L2PcInstance) _actor).getPet().broadcastPacket(new AutoAttackStart(((L2PcInstance) _actor).getPet().getObjectId()));
+ }
+ // Send a Server->Client packet AutoAttackStart to the actor and all L2PcInstance in its _knownPlayers
+ _actor.broadcastPacket(new AutoAttackStart(_actor.getObjectId()));
+ setAutoAttacking(true);
+ }
+ AttackStanceTaskManager.getInstance().addAttackStanceTask(_actor);
+ }
+
+ /**
+ * Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast).
+ *
+ * Caution : Low level function, used by AI subclasses
+ *
+ */
+ public void clientStopAutoAttack()
+ {
+ if (_actor instanceof L2Summon)
+ {
+ L2Summon summon = (L2Summon) _actor;
+ if (summon.getOwner() != null)
+ {
+ summon.getOwner().getAI().clientStopAutoAttack();
+ }
+ return;
+ }
+ if (_actor instanceof L2PcInstance)
+ {
+ if (!AttackStanceTaskManager.getInstance().getAttackStanceTask(_actor) && isAutoAttacking())
+ {
+ AttackStanceTaskManager.getInstance().addAttackStanceTask(_actor);
+ }
+ }
+ else if (isAutoAttacking())
+ {
+ _actor.broadcastPacket(new AutoAttackStop(_actor.getObjectId()));
+ setAutoAttacking(false);
+ }
+ }
+
+ /**
+ * Kill the actor client side by sending Server->Client packet AutoAttackStop, StopMove/StopRotation, Die (broadcast).
+ *
+ * Caution : Low level function, used by AI subclasses
+ *
+ */
+ protected void clientNotifyDead()
+ {
+ // Send a Server->Client packet Die to the actor and all L2PcInstance in its _knownPlayers
+ Die msg = new Die(_actor);
+ _actor.broadcastPacket(msg);
+
+ // Init AI
+ _intention = AI_INTENTION_IDLE;
+ _target = null;
+ _castTarget = null;
+ _attackTarget = null;
+
+ // Cancel the follow task if necessary
+ stopFollow();
+ }
+
+ /**
+ * Update the state of this actor client side by sending Server->Client packet MoveToPawn/CharMoveToLocation and AutoAttackStart to the L2PcInstance player.
+ *
+ * Caution : Low level function, used by AI subclasses
+ *
+ * @param player The L2PcIstance to notify with state of this L2Character
+ */
+ public void describeStateToPlayer(L2PcInstance player)
+ {
+ if (_clientMoving)
+ {
+ if ((_clientMovingToPawnOffset != 0) && (_followTarget != null))
+ {
+ // Send a Server->Client packet MoveToPawn to the actor and all L2PcInstance in its _knownPlayers
+ MoveToPawn msg = new MoveToPawn(_actor, _followTarget, _clientMovingToPawnOffset);
+ player.sendPacket(msg);
+ }
+ else
+ {
+ // Send a Server->Client packet CharMoveToLocation to the actor and all L2PcInstance in its _knownPlayers
+ MoveToLocation msg = new MoveToLocation(_actor);
+ player.sendPacket(msg);
+ }
+ }
+ }
+
+ /**
+ * Create and Launch an AI Follow Task to execute every 1s.
+ *
+ * @param target The L2Character to follow
+ */
+ public synchronized void startFollow(L2Character target)
+ {
+ if (_followTask != null)
+ {
+ _followTask.cancel(false);
+ _followTask = null;
+ }
+
+ // Create and Launch an AI Follow Task to execute every 1s
+ _followTarget = target;
+ _followTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(new FollowTask(), 5, FOLLOW_INTERVAL);
+ }
+
+ /**
+ * Create and Launch an AI Follow Task to execute every 0.5s, following at specified range.
+ *
+ * @param target The L2Character to follow
+ */
+ public synchronized void startFollow(L2Character target, int range)
+ {
+ if (_followTask != null)
+ {
+ _followTask.cancel(false);
+ _followTask = null;
+ }
+
+ _followTarget = target;
+ _followTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(new FollowTask(range), 5, ATTACK_FOLLOW_INTERVAL);
+ }
+
+ /**
+ * Stop an AI Follow Task.
+ *
+ */
+ public synchronized void stopFollow()
+ {
+ if (_followTask != null)
+ {
+ // Stop the Follow Task
+ _followTask.cancel(false);
+ _followTask = null;
+ }
+ _followTarget = null;
+ }
+
+ protected L2Character getFollowTarget()
+ {
+ return _followTarget;
+ }
+
+ protected L2Object getTarget()
+ {
+ return _target;
+ }
+
+ protected void setTarget(L2Object target)
+ {
+ _target = target;
+ }
+
+ /**
+ * Stop all Ai tasks and futures.
+ */
+ public void stopAITask()
+ {
+ stopFollow();
+ }
+
+ @Override
+ public String toString()
+ {
+ if (_actor == null)
+ {
+ return "Actor: null";
+ }
+ return "Actor: " + _actor;
+ }
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/ai/Ctrl.java b/L2J_Server/java/com/l2jserver/gameserver/ai/Ctrl.java
new file mode 100644
index 00000000..d5a19005
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/ai/Ctrl.java
@@ -0,0 +1,55 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.ai;
+
+import com.l2jserver.gameserver.model.actor.L2Character;
+
+/**
+ * Interface of AI and client state. To correctly send messages to client we need it's state. For example, if we've sent 'StartAutoAttack' message, we need to send 'StopAutoAttack' message before any other action. Or if we've sent 'MoveToPawn', we need to send 'StopMove' when the movement of a
+ * character is canceled (by Root spell or any other reason). Thus, we need to know the state of client, i.e. which messages we've sent and how the client will show the scene. Close to this task is the task of AI. If a player's character is attacking a mob, his ATTACK may be iterrupted by an event,
+ * that temporary disable attacking. But when the possibility to ATTACK will be enabled, the character must continue the ATTACK. For mobs it may be more complex, since we want them to decide when to use magic, or when to follow the player for physical combat, or when to escape, to help another mob,
+ * etc. This interface is hiding complexity of server<->client interaction and multiple states of a character. It allows to set a desired, simple "wish" of a character, and the implementation of this interface will take care about the rest. The goal of a character may be like "ATTACK", "random walk"
+ * and so on. To reach the goal inplementation will split it into several small actions, several steps (possibly repeatable). Like "run to target" then "hit it", then if target is not dead - repeat. This flow of simplier steps may be interrupted by incoming events. Like a character's movement was
+ * disabled (by Root spell, for instance). Depending on character's ability AI may choose to wait, or to use magic ATTACK and so on. Additionally incoming events are compared with client's state of the character, and required network messages are sent to client's, i.e. if we have incoming event that
+ * character's movement was disabled, it causes changing if its behavour, and if client's state for the character is "moving" we send messages to clients to stop the avatar/mob.
+ */
+public interface Ctrl
+{
+
+ /** the character this AI serves */
+ L2Character getActor();
+
+ /** get current intention */
+ CtrlIntention getIntention();
+
+ /** get current ATTACK target */
+ L2Character getAttackTarget();
+
+ /** Set general state/intention for AI, with optional data */
+ void setIntention(CtrlIntention intention);
+
+ void setIntention(CtrlIntention intention, Object arg0);
+
+ void setIntention(CtrlIntention intention, Object arg0, Object arg1);
+
+ /**
+ * Event, that notifies about previous step result, or user command, that does not change current general intention
+ */
+ void notifyEvent(CtrlEvent evt);
+
+ void notifyEvent(CtrlEvent evt, Object arg0);
+
+ void notifyEvent(CtrlEvent evt, Object arg0, Object arg1);
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/ai/CtrlEvent.java b/L2J_Server/java/com/l2jserver/gameserver/ai/CtrlEvent.java
new file mode 100644
index 00000000..07c039f4
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/ai/CtrlEvent.java
@@ -0,0 +1,82 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.ai;
+
+/**
+ * This class contains an enum of each possibles evenements that can happen on an AI character.
+ */
+
+public enum CtrlEvent
+{
+ /**
+ * Something has changed, usually a previous step has being completed or maybe was completed, the AI must thing on next action
+ */
+ EVT_THINK,
+ /**
+ * The actor was attacked. This event comes each time a physical or magical attack was done on the actor. NPC may start attack in responce, or ignore this event if they already attack someone, or change target and so on.
+ */
+ EVT_ATTACKED,
+ /** Increase/decrease aggression towards a target, or reduce global aggression if target is null */
+ EVT_AGGRESSION,
+ /** Actor is in stun state */
+ EVT_STUNNED,
+ /** Actor is paralyzed or petrified */
+ EVT_PARALYZED,
+ /** Actor starts/stops sleeping */
+ EVT_SLEEPING,
+ /** Actor is in rooted state (cannot move) */
+ EVT_ROOTED,
+ /** Actor evaded hit **/
+ EVT_EVADED,
+ /**
+ * An event that previous action was completed. The action may be an attempt to physically/magically hit an enemy, or an action that discarded attack attempt has finished.
+ */
+ EVT_READY_TO_ACT,
+ /**
+ * User's command, like using a combat magic or changing weapon, etc. The command is not intended to change final goal
+ */
+ EVT_USER_CMD,
+ /**
+ * The actor arrived to assigned location, or it's a time to modify movement destination (follow, interact, random move and others intentions).
+ */
+ EVT_ARRIVED,
+ /**
+ * The actor arrived to an intermidiate point, and needs revalidate destination. This is sent when follow/move to pawn if destination is far away.
+ */
+ EVT_ARRIVED_REVALIDATE,
+ /** The actor cannot move anymore. */
+ EVT_ARRIVED_BLOCKED,
+ /** Forgets an object (if it's used as attack target, follow target and so on */
+ EVT_FORGET_OBJECT,
+ /**
+ * Attempt to cancel current step execution, but not change the intention. For example, the actor was putted into a stun, so it's current attack or movement has to be canceled. But after the stun state expired, the actor may try to attack again. Another usage for CANCEL is a user's attempt to
+ * cancel a cast/bow attack and so on.
+ */
+ EVT_CANCEL,
+ /** The character is dead */
+ EVT_DEAD,
+ /** The character looks like dead */
+ EVT_FAKE_DEATH,
+ /** The character attack anyone randomly **/
+ EVT_CONFUSED,
+ /** The character cannot cast spells anymore **/
+ EVT_MUTED,
+ /** The character flee in randoms directions **/
+ EVT_AFRAID,
+ /** The character finish casting **/
+ EVT_FINISH_CASTING,
+ /** The character betrayed its master */
+ EVT_BETRAYED
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/ai/CtrlIntention.java b/L2J_Server/java/com/l2jserver/gameserver/ai/CtrlIntention.java
new file mode 100644
index 00000000..7c7c7ee1
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/ai/CtrlIntention.java
@@ -0,0 +1,43 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.ai;
+
+/**
+ * Enumaration of generic intentions of an NPC/PC, an intention may require several steps to be completed
+ */
+
+public enum CtrlIntention
+{
+ /** Do nothing, disconnect AI of NPC if no players around */
+ AI_INTENTION_IDLE,
+ /** Alerted state without goal : scan attackable targets, random walk, etc */
+ AI_INTENTION_ACTIVE,
+ /** Rest (sit until attacked) */
+ AI_INTENTION_REST,
+ /**
+ * Attack target (cast combat magic, go to target, combat), may be ignored, if target is locked on another character or a peacefull zone and so on
+ */
+ AI_INTENTION_ATTACK,
+ /** Cast a spell, depending on the spell - may start or stop attacking */
+ AI_INTENTION_CAST,
+ /** Just move to another location */
+ AI_INTENTION_MOVE_TO,
+ /** Like move, but check target's movement and follow it */
+ AI_INTENTION_FOLLOW,
+ /** PickUp and item, (got to item, pickup it, become idle */
+ AI_INTENTION_PICK_UP,
+ /** Move to target, then interact */
+ AI_INTENTION_INTERACT;
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/ai/L2AirShipAI.java b/L2J_Server/java/com/l2jserver/gameserver/ai/L2AirShipAI.java
new file mode 100644
index 00000000..67cf196f
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/ai/L2AirShipAI.java
@@ -0,0 +1,73 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.ai;
+
+import com.l2jserver.gameserver.model.L2CharPosition;
+import com.l2jserver.gameserver.model.actor.instance.L2AirShipInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.network.serverpackets.ExMoveToLocationAirShip;
+import com.l2jserver.gameserver.network.serverpackets.ExStopMoveAirShip;
+
+/**
+ * @author DS
+ */
+public class L2AirShipAI extends L2VehicleAI
+{
+ public L2AirShipAI(L2AirShipInstance.AIAccessor accessor)
+ {
+ super(accessor);
+ }
+
+ @Override
+ protected void moveTo(int x, int y, int z)
+ {
+ if (!_actor.isMovementDisabled())
+ {
+ _clientMoving = true;
+ _accessor.moveTo(x, y, z);
+ _actor.broadcastPacket(new ExMoveToLocationAirShip(getActor()));
+ }
+ }
+
+ @Override
+ protected void clientStopMoving(L2CharPosition pos)
+ {
+ if (_actor.isMoving())
+ {
+ _accessor.stopMove(pos);
+ }
+
+ if (_clientMoving || (pos != null))
+ {
+ _clientMoving = false;
+ _actor.broadcastPacket(new ExStopMoveAirShip(getActor()));
+ }
+ }
+
+ @Override
+ public void describeStateToPlayer(L2PcInstance player)
+ {
+ if (_clientMoving)
+ {
+ player.sendPacket(new ExMoveToLocationAirShip(getActor()));
+ }
+ }
+
+ @Override
+ public L2AirShipInstance getActor()
+ {
+ return (L2AirShipInstance) _actor;
+ }
+}
\ No newline at end of file
diff --git a/L2J_Server/java/com/l2jserver/gameserver/ai/L2AttackableAI.java b/L2J_Server/java/com/l2jserver/gameserver/ai/L2AttackableAI.java
new file mode 100644
index 00000000..a3ed77e0
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/ai/L2AttackableAI.java
@@ -0,0 +1,2840 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.ai;
+
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
+
+import java.util.Collection;
+import java.util.concurrent.Future;
+import java.util.logging.Level;
+
+import com.l2jserver.Config;
+import com.l2jserver.gameserver.GameTimeController;
+import com.l2jserver.gameserver.GeoData;
+import com.l2jserver.gameserver.Territory;
+import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.datatables.NpcTable;
+import com.l2jserver.gameserver.instancemanager.DimensionalRiftManager;
+import com.l2jserver.gameserver.model.L2CharPosition;
+import com.l2jserver.gameserver.model.L2Object;
+import com.l2jserver.gameserver.model.L2Skill;
+import com.l2jserver.gameserver.model.L2Skill.SkillTargetType;
+import com.l2jserver.gameserver.model.actor.L2Attackable;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.actor.L2Npc;
+import com.l2jserver.gameserver.model.actor.L2Playable;
+import com.l2jserver.gameserver.model.actor.L2Summon;
+import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2FestivalMonsterInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2FriendlyMobInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2GrandBossInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2GuardInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2MonsterInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2RaidBossInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2RiftInvaderInstance;
+import com.l2jserver.gameserver.model.quest.Quest;
+import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;
+import com.l2jserver.gameserver.templates.chars.L2NpcTemplate.AIType;
+import com.l2jserver.gameserver.templates.skills.L2EffectType;
+import com.l2jserver.gameserver.templates.skills.L2SkillType;
+import com.l2jserver.gameserver.util.Util;
+import com.l2jserver.util.Rnd;
+
+/**
+ * This class manages AI of L2Attackable.
+ *
+ */
+public class L2AttackableAI extends L2CharacterAI implements Runnable
+{
+
+ // protected static final Logger _log = Logger.getLogger(L2AttackableAI.class.getName());
+
+ private static final int RANDOM_WALK_RATE = 30; // confirmed
+ // private static final int MAX_DRIFT_RANGE = 300;
+ private static final int MAX_ATTACK_TIMEOUT = 1200; // int ticks, i.e. 2min
+
+ /** The L2Attackable AI task executed every 1s (call onEvtThink method) */
+ private Future> _aiTask;
+
+ /** The delay after which the attacked is stopped */
+ private int _attackTimeout;
+
+ /** The L2Attackable aggro counter */
+ private int _globalAggro;
+
+ /** The flag used to indicate that a thinking action is in progress */
+ private boolean _thinking; // to prevent recursive thinking
+
+ private int timepass = 0;
+ private int chaostime = 0;
+ private final L2NpcTemplate _skillrender;
+ int lastBuffTick;
+
+ /**
+ * Constructor of L2AttackableAI.
+ *
+ * @param accessor The AI accessor of the L2Character
+ */
+ public L2AttackableAI(L2Character.AIAccessor accessor)
+ {
+ super(accessor);
+ _skillrender = NpcTable.getInstance().getTemplate(getActiveChar().getTemplate().npcId);
+ // _selfAnalysis.init();
+ _attackTimeout = Integer.MAX_VALUE;
+ _globalAggro = -10; // 10 seconds timeout of ATTACK after respawn
+ }
+
+ @Override
+ public void run()
+ {
+ // Launch actions corresponding to the Event Think
+ onEvtThink();
+
+ }
+
+ /**
+ * Return True if the target is autoattackable (depends on the actor type).
+ *
+ * Actor is a L2GuardInstance :
+ *
+ *
The target isn't a Folk or a Door
The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)
The target is in the actor Aggro range and is at the same height
The L2PcInstance target has karma (=PK)
The L2MonsterInstance
+ * target is aggressive
+ *
+ * Actor is a L2SiegeGuardInstance :
+ *
+ *
The target isn't a Folk or a Door
The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)
The target is in the actor Aggro range and is at the same height
A siege is in progress
The L2PcInstance target isn't a Defender
+ *
+ *
+ * Actor is a L2FriendlyMobInstance :
+ *
+ *
The target isn't a Folk, a Door or another L2Npc
The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)
The target is in the actor Aggro range and is at the same height
The L2PcInstance target has karma (=PK)
+ *
+ * Actor is a L2MonsterInstance :
+ *
+ *
The target isn't a Folk, a Door or another L2Npc
The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)
The target is in the actor Aggro range and is at the same height
The actor is Aggressive
+ *
+ * @param target The targeted L2Object
+ */
+ private boolean autoAttackCondition(L2Character target)
+ {
+ if ((target == null) || (getActiveChar() == null))
+ {
+ return false;
+ }
+
+ L2Attackable me = getActiveChar();
+
+ // Check if the target isn't invulnerable
+ if (target.isInvul())
+ {
+ // However EffectInvincible requires to check GMs specially
+ if ((target instanceof L2PcInstance) && ((L2PcInstance) target).isGM())
+ {
+ return false;
+ }
+ if ((target instanceof L2Summon) && ((L2Summon) target).getOwner().isGM())
+ {
+ return false;
+ }
+ }
+
+ // Check if the target isn't a Folk or a Door
+ if (target instanceof L2DoorInstance)
+ {
+ return false;
+ }
+
+ // Check if the target isn't dead, is in the Aggro range and is at the same height
+ if (target.isAlikeDead() || ((target instanceof L2Playable) && !me.isInsideRadius(target, me.getAggroRange(), true, false)))
+ {
+ return false;
+ }
+
+ // Check if the target is a L2PlayableInstance
+ if (target instanceof L2Playable)
+ {
+ // Check if the AI isn't a Raid Boss, can See Silent Moving players and the target isn't in silent move mode
+ if (!(me.isRaid()) && !(me.canSeeThroughSilentMove()) && ((L2Playable) target).isSilentMoving())
+ {
+ return false;
+ }
+ }
+
+ // Check if the target is a L2PcInstance
+ if (target instanceof L2PcInstance)
+ {
+ // Don't take the aggro if the GM has the access level below or equal to GM_DONT_TAKE_AGGRO
+ if (((L2PcInstance) target).isGM() && !((L2PcInstance) target).getAccessLevel().canTakeAggro())
+ {
+ return false;
+ }
+
+ // TODO: Ideally, autoattack condition should be called from the AI script. In that case,
+ // it should only implement the basic behaviors while the script will add more specific
+ // behaviors (like varka/ketra alliance, etc). Once implemented, remove specialized stuff
+ // from this location. (Fulminus)
+
+ // Check if player is an ally (comparing mem addr)
+ if ("varka_silenos_clan".equals(me.getFactionId()) && ((L2PcInstance) target).isAlliedWithVarka())
+ {
+ return false;
+ }
+ if ("ketra_orc_clan".equals(me.getFactionId()) && ((L2PcInstance) target).isAlliedWithKetra())
+ {
+ return false;
+ }
+ // check if the target is within the grace period for JUST getting up from fake death
+ if (((L2PcInstance) target).isRecentFakeDeath())
+ {
+ return false;
+ }
+
+ if (target.isInParty() && target.getParty().isInDimensionalRift())
+ {
+ byte riftType = target.getParty().getDimensionalRift().getType();
+ byte riftRoom = target.getParty().getDimensionalRift().getCurrentRoom();
+
+ if ((me instanceof L2RiftInvaderInstance) && !DimensionalRiftManager.getInstance().getRoom(riftType, riftRoom).checkIfInZone(me.getX(), me.getY(), me.getZ()))
+ {
+ return false;
+ }
+ }
+
+ // if (_selfAnalysis.cannotMoveOnLand && !target.isInsideZone(L2Character.ZONE_WATER))
+ // return false;
+ }
+
+ // Check if the target is a L2Summon
+ if (target instanceof L2Summon)
+ {
+ L2PcInstance owner = ((L2Summon) target).getOwner();
+ if (owner != null)
+ {
+ // Don't take the aggro if the GM has the access level below or equal to GM_DONT_TAKE_AGGRO
+ if (owner.isGM() && (owner.isInvul() || !owner.getAccessLevel().canTakeAggro()))
+ {
+ return false;
+ }
+ // Check if player is an ally (comparing mem addr)
+ if ("varka_silenos_clan".equals(me.getFactionId()) && owner.isAlliedWithVarka())
+ {
+ return false;
+ }
+ if ("ketra_orc_clan".equals(me.getFactionId()) && owner.isAlliedWithKetra())
+ {
+ return false;
+ }
+ }
+ }
+ // Check if the actor is a L2GuardInstance
+ if (getActiveChar() instanceof L2GuardInstance)
+ {
+
+ // Check if the L2PcInstance target has karma (=PK)
+ if ((target instanceof L2PcInstance) && (((L2PcInstance) target).getKarma() > 0))
+ {
+ // Los Check
+ return GeoData.getInstance().canSeeTarget(me, target);
+ }
+
+ // if (target instanceof L2Summon)
+ // return ((L2Summon)target).getKarma() > 0;
+
+ // Check if the L2MonsterInstance target is aggressive
+ if ((target instanceof L2MonsterInstance) && Config.GUARD_ATTACK_AGGRO_MOB)
+ {
+ return (((L2MonsterInstance) target).isAggressive() && GeoData.getInstance().canSeeTarget(me, target));
+ }
+
+ return false;
+ }
+ else if (getActiveChar() instanceof L2FriendlyMobInstance)
+ { // the actor is a L2FriendlyMobInstance
+
+ // Check if the target isn't another L2Npc
+ if (target instanceof L2Npc)
+ {
+ return false;
+ }
+
+ // Check if the L2PcInstance target has karma (=PK)
+ if ((target instanceof L2PcInstance) && (((L2PcInstance) target).getKarma() > 0))
+ {
+ return GeoData.getInstance().canSeeTarget(me, target); // Los Check
+ }
+ return false;
+ }
+ else
+ {
+ if (target instanceof L2Attackable)
+ {
+ if ((getActiveChar().getEnemyClan() == null) || (((L2Attackable) target).getClan() == null))
+ {
+ return false;
+ }
+
+ if (!target.isAutoAttackable(getActiveChar()))
+ {
+ return false;
+ }
+
+ if (getActiveChar().getEnemyClan().equals(((L2Attackable) target).getClan()))
+ {
+ if (getActiveChar().isInsideRadius(target, getActiveChar().getEnemyRange(), false, false))
+ {
+ return GeoData.getInstance().canSeeTarget(getActiveChar(), target);
+ }
+ return false;
+ }
+ if ((getActiveChar().getIsChaos() > 0) && me.isInsideRadius(target, getActiveChar().getIsChaos(), false, false))
+ {
+ if ((getActiveChar().getFactionId() != null) && getActiveChar().getFactionId().equals(((L2Attackable) target).getFactionId()))
+ {
+ return false;
+ }
+ // Los Check
+ return GeoData.getInstance().canSeeTarget(me, target);
+ }
+ }
+
+ if ((target instanceof L2Attackable) || (target instanceof L2Npc))
+ {
+ return false;
+ }
+
+ // depending on config, do not allow mobs to attack _new_ players in peacezones,
+ // unless they are already following those players from outside the peacezone.
+ if (!Config.ALT_MOB_AGRO_IN_PEACEZONE && target.isInsideZone(L2Character.ZONE_PEACE))
+ {
+ return false;
+ }
+
+ if (me.isChampion() && Config.L2JMOD_CHAMPION_PASSIVE)
+ {
+ return false;
+ }
+
+ // Check if the actor is Aggressive
+ return (me.isAggressive() && GeoData.getInstance().canSeeTarget(me, target));
+ }
+ }
+
+ public void startAITask()
+ {
+ // If not idle - create an AI task (schedule onEvtThink repeatedly)
+ if (_aiTask == null)
+ {
+ _aiTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(this, 1000, 1000);
+ }
+ }
+
+ @Override
+ public void stopAITask()
+ {
+ if (_aiTask != null)
+ {
+ _aiTask.cancel(false);
+ _aiTask = null;
+ }
+ super.stopAITask();
+ }
+
+ /**
+ * Set the Intention of this L2CharacterAI and create an AI Task executed every 1s (call onEvtThink method) for this L2Attackable.
+ *
+ * Caution : If actor _knowPlayer isn't EMPTY, AI_INTENTION_IDLE will be change in AI_INTENTION_ACTIVE
+ *
+ * @param intention The new Intention to set to the AI
+ * @param arg0 The first parameter of the Intention
+ * @param arg1 The second parameter of the Intention
+ */
+ @Override
+ synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
+ {
+ if ((intention == AI_INTENTION_IDLE) || (intention == AI_INTENTION_ACTIVE))
+ {
+ // Check if actor is not dead
+ L2Attackable npc = getActiveChar();
+ if (!npc.isAlikeDead())
+ {
+ // If its _knownPlayer isn't empty set the Intention to AI_INTENTION_ACTIVE
+ if (!npc.getKnownList().getKnownPlayers().isEmpty())
+ {
+ intention = AI_INTENTION_ACTIVE;
+ }
+ else
+ {
+ if (npc.getSpawn() != null)
+ {
+ final int range = Config.MAX_DRIFT_RANGE;
+ if (!npc.isInsideRadius(npc.getSpawn().getLocx(), npc.getSpawn().getLocy(), npc.getSpawn().getLocz(), range + range, true, false))
+ {
+ intention = AI_INTENTION_ACTIVE;
+ }
+ }
+ }
+ }
+
+ if (intention == AI_INTENTION_IDLE)
+ {
+ // Set the Intention of this L2AttackableAI to AI_INTENTION_IDLE
+ super.changeIntention(AI_INTENTION_IDLE, null, null);
+
+ // Stop AI task and detach AI from NPC
+ if (_aiTask != null)
+ {
+ _aiTask.cancel(true);
+ _aiTask = null;
+ }
+
+ // Cancel the AI
+ _accessor.detachAI();
+
+ return;
+ }
+ }
+
+ // Set the Intention of this L2AttackableAI to intention
+ super.changeIntention(intention, arg0, arg1);
+
+ // If not idle - create an AI task (schedule onEvtThink repeatedly)
+ startAITask();
+ }
+
+ /**
+ * Manage the Attack Intention : Stop current Attack (if necessary), Calculate attack timeout, Start a new Attack and Launch Think Event.
+ *
+ * @param target The L2Character to attack
+ */
+ @Override
+ protected void onIntentionAttack(L2Character target)
+ {
+ // Calculate the attack timeout
+ _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
+
+ // self and buffs
+
+ if ((lastBuffTick + 30) < GameTimeController.getGameTicks())
+ {
+ if (_skillrender.hasBuffSkill())
+ {
+ for (L2Skill sk : _skillrender._buffskills)
+ {
+ if (cast(sk))
+ {
+ break;
+ }
+ }
+ }
+
+ lastBuffTick = GameTimeController.getGameTicks();
+ }
+
+ // Manage the Attack Intention : Stop current Attack (if necessary), Start a new Attack and Launch Think Event
+ super.onIntentionAttack(target);
+ }
+
+ private void thinkCast()
+ {
+ if (checkTargetLost(getCastTarget()))
+ {
+ setCastTarget(null);
+ return;
+ }
+ if (maybeMoveToPawn(getCastTarget(), _actor.getMagicalAttackRange(_skill)))
+ {
+ return;
+ }
+ clientStopMoving(null);
+ setIntention(AI_INTENTION_ACTIVE);
+ _accessor.doCast(_skill);
+ }
+
+ /**
+ * Manage AI standard thinks of a L2Attackable (called by onEvtThink).
+ *
+ * Actions :
+ *
+ *
Update every 1s the _globalAggro counter to come close to 0
If the actor is Aggressive and can attack, add all autoAttackable L2Character in its Aggro Range to its _aggroList, chose a target and order to attack it
If the actor is a L2GuardInstance that can't attack,
+ * order to it to return to its home location
If the actor is a L2MonsterInstance that can't attack, order to it to random walk (1/100)
+ *
+ */
+ private void thinkActive()
+ {
+ L2Attackable npc = getActiveChar();
+
+ // Update every 1s the _globalAggro counter to come close to 0
+ if (_globalAggro != 0)
+ {
+ if (_globalAggro < 0)
+ {
+ _globalAggro++;
+ }
+ else
+ {
+ _globalAggro--;
+ }
+ }
+
+ // Add all autoAttackable L2Character in L2Attackable Aggro Range to its _aggroList with 0 damage and 1 hate
+ // A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10
+ if (_globalAggro >= 0)
+ {
+ // Get all visible objects inside its Aggro Range
+ Collection objs = npc.getKnownList().getKnownObjects().values();
+ // synchronized (npc.getKnownList().getKnownObjects())
+ {
+ for (L2Object obj : objs)
+ {
+ if (!(obj instanceof L2Character))
+ {
+ continue;
+ }
+ L2Character target = (L2Character) obj;
+
+ /*
+ * Check to see if this is a festival mob spawn. If it is, then check to see if the aggro trigger is a festival participant...if so, move to attack it.
+ */
+ if ((npc instanceof L2FestivalMonsterInstance) && (obj instanceof L2PcInstance))
+ {
+ L2PcInstance targetPlayer = (L2PcInstance) obj;
+
+ if (!(targetPlayer.isFestivalParticipant()))
+ {
+ continue;
+ }
+ }
+
+ // TODO: The AI Script ought to handle aggro behaviors in onSee. Once implemented, aggro behaviors ought
+ // to be removed from here. (Fulminus)
+ // For each L2Character check if the target is autoattackable
+ if (autoAttackCondition(target)) // check aggression
+ {
+ // Get the hate level of the L2Attackable against this L2Character target contained in _aggroList
+ int hating = npc.getHating(target);
+
+ // Add the attacker to the L2Attackable _aggroList with 0 damage and 1 hate
+ if (hating == 0)
+ {
+ npc.addDamageHate(target, 0, 0);
+ }
+ }
+ }
+ }
+
+ // Chose a target from its aggroList
+ L2Character hated;
+ if (npc.isConfused())
+ {
+ hated = getAttackTarget(); // effect handles selection
+ }
+ else
+ {
+ hated = npc.getMostHated();
+ }
+
+ // Order to the L2Attackable to attack the target
+ if ((hated != null) && !npc.isCoreAIDisabled())
+ {
+ // Get the hate level of the L2Attackable against this L2Character target contained in _aggroList
+ int aggro = npc.getHating(hated);
+
+ if ((aggro + _globalAggro) > 0)
+ {
+ // Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
+ if (!npc.isRunning())
+ {
+ npc.setRunning();
+ }
+
+ // Set the AI Intention to AI_INTENTION_ATTACK
+ setIntention(CtrlIntention.AI_INTENTION_ATTACK, hated);
+ }
+
+ return;
+ }
+ }
+
+ // Chance to forget attackers after some time
+ if ((npc.getCurrentHp() == npc.getMaxHp()) && (npc.getCurrentMp() == npc.getMaxMp()) && !npc.getAttackByList().isEmpty() && (Rnd.nextInt(500) == 0))
+ {
+ npc.clearAggroList();
+ npc.getAttackByList().clear();
+ if (npc instanceof L2MonsterInstance)
+ {
+ if (((L2MonsterInstance) npc).hasMinions())
+ {
+ ((L2MonsterInstance) npc).getMinionList().deleteReusedMinions();
+ }
+ }
+ }
+
+ // Check if the actor is a L2GuardInstance
+ if (npc instanceof L2GuardInstance)
+ {
+ // Order to the L2GuardInstance to return to its home location because there's no target to attack
+ ((L2GuardInstance) npc).returnHome();
+ }
+
+ // If this is a festival monster, then it remains in the same location.
+ if (npc instanceof L2FestivalMonsterInstance)
+ {
+ return;
+ }
+
+ // Check if the mob should not return to spawn point
+ if (!npc.canReturnToSpawnPoint())
+ {
+ return;
+ }
+
+ // Minions following leader
+ final L2Character leader = npc.getLeader();
+ if ((leader != null) && !leader.isAlikeDead())
+ {
+ final int offset;
+ final int minRadius = 30;
+
+ if (npc.isRaidMinion())
+ {
+ offset = 500; // for Raids - need correction
+ }
+ else
+ {
+ offset = 200; // for normal minions - need correction :)
+ }
+
+ if (leader.isRunning())
+ {
+ npc.setRunning();
+ }
+ else
+ {
+ npc.setWalking();
+ }
+
+ if (npc.getPlanDistanceSq(leader) > (offset * offset))
+ {
+ int x1, y1, z1;
+ x1 = Rnd.get(minRadius * 2, offset * 2); // x
+ y1 = Rnd.get(x1, offset * 2); // distance
+ y1 = (int) Math.sqrt((y1 * y1) - (x1 * x1)); // y
+ if (x1 > (offset + minRadius))
+ {
+ x1 = (leader.getX() + x1) - offset;
+ }
+ else
+ {
+ x1 = (leader.getX() - x1) + minRadius;
+ }
+ if (y1 > (offset + minRadius))
+ {
+ y1 = (leader.getY() + y1) - offset;
+ }
+ else
+ {
+ y1 = (leader.getY() - y1) + minRadius;
+ }
+
+ z1 = leader.getZ();
+ // Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast)
+ moveTo(x1, y1, z1);
+ return;
+ }
+ else if (Rnd.nextInt(RANDOM_WALK_RATE) == 0)
+ {
+ if (_skillrender.hasBuffSkill())
+ {
+ for (L2Skill sk : _skillrender._buffskills)
+ {
+ if (cast(sk))
+ {
+ return;
+ }
+ }
+ }
+ }
+ }
+ // Order to the L2MonsterInstance to random walk (1/100)
+ else if ((npc.getSpawn() != null) && (Rnd.nextInt(RANDOM_WALK_RATE) == 0) && !npc.isNoRndWalk())
+ {
+ int x1, y1, z1;
+ final int range = Config.MAX_DRIFT_RANGE;
+
+ if (_skillrender.hasBuffSkill())
+ {
+ for (L2Skill sk : _skillrender._buffskills)
+ {
+ if (cast(sk))
+ {
+ return;
+ }
+ }
+ }
+
+ // If NPC with random coord in territory
+ if ((npc.getSpawn().getLocx() == 0) && (npc.getSpawn().getLocy() == 0))
+ {
+ // Calculate a destination point in the spawn area
+ int p[] = Territory.getInstance().getRandomPoint(npc.getSpawn().getLocation());
+ x1 = p[0];
+ y1 = p[1];
+ z1 = p[2];
+
+ // Calculate the distance between the current position of the L2Character and the target (x,y)
+ double distance2 = npc.getPlanDistanceSq(x1, y1);
+
+ if (distance2 > ((range + range) * (range + range)))
+ {
+ npc.setisReturningToSpawnPoint(true);
+ float delay = (float) Math.sqrt(distance2) / range;
+ x1 = npc.getX() + (int) ((x1 - npc.getX()) / delay);
+ y1 = npc.getY() + (int) ((y1 - npc.getY()) / delay);
+ }
+
+ // If NPC with random fixed coord, don't move (unless needs to return to spawnpoint)
+ if ((Territory.getInstance().getProcMax(npc.getSpawn().getLocation()) > 0) && !npc.isReturningToSpawnPoint())
+ {
+ return;
+ }
+ }
+ else
+ {
+ // If NPC with fixed coord
+ x1 = npc.getSpawn().getLocx();
+ y1 = npc.getSpawn().getLocy();
+ z1 = npc.getSpawn().getLocz();
+
+ if (!npc.isInsideRadius(x1, y1, range, false))
+ {
+ npc.setisReturningToSpawnPoint(true);
+ }
+ else
+ {
+ x1 = Rnd.nextInt(range * 2); // x
+ y1 = Rnd.get(x1, range * 2); // distance
+ y1 = (int) Math.sqrt((y1 * y1) - (x1 * x1)); // y
+ x1 += npc.getSpawn().getLocx() - range;
+ y1 += npc.getSpawn().getLocy() - range;
+ z1 = npc.getZ();
+ }
+ }
+
+ // _log.debug("Current pos ("+getX()+", "+getY()+"), moving to ("+x1+", "+y1+").");
+ // Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast)
+ moveTo(x1, y1, z1);
+ }
+ }
+
+ /**
+ * Manage AI attack thinks of a L2Attackable (called by onEvtThink).
+ *
+ * Actions :
+ *
+ *
Update the attack timeout if actor is running
If target is dead or timeout is expired, stop this attack and set the Intention to AI_INTENTION_ACTIVE
Call all L2Object of its Faction inside the Faction Range
Chose a target and order to attack it with magic skill
+ * or physical attack
Init the attack : Calculate the attack timeout, Set the _globalAggro to 0, Add the attacker to the actor _aggroList
Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
Set the Intention to AI_INTENTION_ATTACK
+ *
+ *
+ * @param attacker The L2Character that attacks the actor
+ */
+ @Override
+ protected void onEvtAttacked(L2Character attacker)
+ {
+ L2Attackable me = getActiveChar();
+
+ // Calculate the attack timeout
+ _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
+
+ // Set the _globalAggro to 0 to permit attack even just after spawn
+ if (_globalAggro < 0)
+ {
+ _globalAggro = 0;
+ }
+
+ // Add the attacker to the _aggroList of the actor
+ me.addDamageHate(attacker, 0, 1);
+
+ // Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
+ if (!me.isRunning())
+ {
+ me.setRunning();
+ }
+
+ // Set the Intention to AI_INTENTION_ATTACK
+ if (getIntention() != AI_INTENTION_ATTACK)
+ {
+ setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker);
+ }
+ else if (me.getMostHated() != getAttackTarget())
+ {
+ setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker);
+ }
+
+ if (me instanceof L2MonsterInstance)
+ {
+ L2MonsterInstance master = (L2MonsterInstance) me;
+
+ if (master.hasMinions())
+ {
+ master.getMinionList().onAssist(me, attacker);
+ }
+
+ master = master.getLeader();
+ if ((master != null) && master.hasMinions())
+ {
+ master.getMinionList().onAssist(me, attacker);
+ }
+ }
+
+ super.onEvtAttacked(attacker);
+ }
+
+ /**
+ * Launch actions corresponding to the Event Aggression.
+ *
+ * Actions :
+ *
+ *
Add the target to the actor _aggroList or update hate if already present
Set the actor Intention to AI_INTENTION_ATTACK (if actor is L2GuardInstance check if it isn't too far from its home location)
+ *
+ * @param attacker The L2Character that attacks
+ * @param aggro The value of hate to add to the actor against the target
+ */
+ @Override
+ protected void onEvtAggression(L2Character target, int aggro)
+ {
+ L2Attackable me = getActiveChar();
+
+ if (target != null)
+ {
+ // Add the target to the actor _aggroList or update hate if already present
+ me.addDamageHate(target, 0, aggro);
+
+ // Set the actor AI Intention to AI_INTENTION_ATTACK
+ if (getIntention() != CtrlIntention.AI_INTENTION_ATTACK)
+ {
+ // Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
+ if (!me.isRunning())
+ {
+ me.setRunning();
+ }
+
+ setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
+ }
+
+ if (me instanceof L2MonsterInstance)
+ {
+ L2MonsterInstance master = (L2MonsterInstance) me;
+
+ if (master.hasMinions())
+ {
+ master.getMinionList().onAssist(me, target);
+ }
+
+ master = master.getLeader();
+ if ((master != null) && master.hasMinions())
+ {
+ master.getMinionList().onAssist(me, target);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onIntentionActive()
+ {
+ // Cancel attack timeout
+ _attackTimeout = Integer.MAX_VALUE;
+ super.onIntentionActive();
+ }
+
+ public void setGlobalAggro(int value)
+ {
+ _globalAggro = value;
+ }
+
+ /**
+ * @param timepass The timepass to set.
+ */
+ public void setTimepass(int TP)
+ {
+ timepass = TP;
+ }
+
+ /**
+ * @return Returns the timepass.
+ */
+ public int getTimepass()
+ {
+ return timepass;
+ }
+
+ public L2Attackable getActiveChar()
+ {
+ return (L2Attackable) _actor;
+ }
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/ai/L2BoatAI.java b/L2J_Server/java/com/l2jserver/gameserver/ai/L2BoatAI.java
new file mode 100644
index 00000000..71a1150f
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/ai/L2BoatAI.java
@@ -0,0 +1,80 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.ai;
+
+import com.l2jserver.gameserver.model.L2CharPosition;
+import com.l2jserver.gameserver.model.actor.instance.L2BoatInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.network.serverpackets.VehicleDeparture;
+import com.l2jserver.gameserver.network.serverpackets.VehicleInfo;
+import com.l2jserver.gameserver.network.serverpackets.VehicleStarted;
+
+/**
+ * @author DS
+ */
+public class L2BoatAI extends L2VehicleAI
+{
+ public L2BoatAI(L2BoatInstance.AIAccessor accessor)
+ {
+ super(accessor);
+ }
+
+ @Override
+ protected void moveTo(int x, int y, int z)
+ {
+ if (!_actor.isMovementDisabled())
+ {
+ if (!_clientMoving)
+ {
+ _actor.broadcastPacket(new VehicleStarted(getActor(), 1));
+ }
+
+ _clientMoving = true;
+ _accessor.moveTo(x, y, z);
+ _actor.broadcastPacket(new VehicleDeparture(getActor()));
+ }
+ }
+
+ @Override
+ protected void clientStopMoving(L2CharPosition pos)
+ {
+ if (_actor.isMoving())
+ {
+ _accessor.stopMove(pos);
+ }
+
+ if (_clientMoving || (pos != null))
+ {
+ _clientMoving = false;
+ _actor.broadcastPacket(new VehicleStarted(getActor(), 0));
+ _actor.broadcastPacket(new VehicleInfo(getActor()));
+ }
+ }
+
+ @Override
+ public void describeStateToPlayer(L2PcInstance player)
+ {
+ if (_clientMoving)
+ {
+ player.sendPacket(new VehicleDeparture(getActor()));
+ }
+ }
+
+ @Override
+ public L2BoatInstance getActor()
+ {
+ return (L2BoatInstance) _actor;
+ }
+}
\ No newline at end of file
diff --git a/L2J_Server/java/com/l2jserver/gameserver/ai/L2CharacterAI.java b/L2J_Server/java/com/l2jserver/gameserver/ai/L2CharacterAI.java
new file mode 100644
index 00000000..f9adaf18
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/ai/L2CharacterAI.java
@@ -0,0 +1,1611 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.ai;
+
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_CAST;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_INTERACT;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_MOVE_TO;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_PICK_UP;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_REST;
+
+import java.util.List;
+
+import javolution.util.FastList;
+
+import com.l2jserver.Config;
+import com.l2jserver.gameserver.GeoData;
+import com.l2jserver.gameserver.model.L2CharPosition;
+import com.l2jserver.gameserver.model.L2Effect;
+import com.l2jserver.gameserver.model.L2ItemInstance;
+import com.l2jserver.gameserver.model.L2ItemInstance.ItemLocation;
+import com.l2jserver.gameserver.model.L2Object;
+import com.l2jserver.gameserver.model.L2Skill;
+import com.l2jserver.gameserver.model.actor.L2Attackable;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.actor.L2Npc;
+import com.l2jserver.gameserver.model.actor.L2Playable;
+import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.network.SystemMessageId;
+import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
+import com.l2jserver.gameserver.network.serverpackets.AutoAttackStop;
+import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
+import com.l2jserver.gameserver.taskmanager.AttackStanceTaskManager;
+import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;
+import com.l2jserver.gameserver.templates.item.L2Weapon;
+import com.l2jserver.gameserver.templates.item.L2WeaponType;
+import com.l2jserver.gameserver.templates.skills.L2SkillType;
+import com.l2jserver.util.Point3D;
+import com.l2jserver.util.Rnd;
+
+/**
+ * This class manages AI of L2Character.
+ *
+ * L2CharacterAI :
+ *
+ *
L2AttackableAI
L2DoorAI
L2PlayerAI
L2SummonAI
+ *
+ */
+public class L2CharacterAI extends AbstractAI
+{
+ public static class IntentionCommand
+ {
+ protected final CtrlIntention _crtlIntention;
+ protected final Object _arg0, _arg1;
+
+ protected IntentionCommand(CtrlIntention pIntention, Object pArg0, Object pArg1)
+ {
+ _crtlIntention = pIntention;
+ _arg0 = pArg0;
+ _arg1 = pArg1;
+ }
+
+ public CtrlIntention getCtrlIntention()
+ {
+ return _crtlIntention;
+ }
+ }
+
+ /**
+ * Constructor of L2CharacterAI.
+ *
+ * @param accessor The AI accessor of the L2Character
+ */
+ public L2CharacterAI(L2Character.AIAccessor accessor)
+ {
+ super(accessor);
+ }
+
+ public IntentionCommand getNextIntention()
+ {
+ return null;
+ }
+
+ @Override
+ protected void onEvtAttacked(L2Character attacker)
+ {
+ if ((attacker instanceof L2Attackable) && !((L2Attackable) attacker).isCoreAIDisabled())
+ {
+ clientStartAutoAttack();
+ }
+ }
+
+ /**
+ * Manage the Idle Intention : Stop Attack, Movement and Stand Up the actor.
+ *
+ * Actions :
+ *
+ *
Set the AI Intention to AI_INTENTION_IDLE
Init cast and attack target
Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
Stop the actor movement server side AND client side by sending Server->Client packet
+ * StopMove/StopRotation (broadcast)
Stand up the actor server side AND client side by sending Server->Client packet ChangeWaitType (broadcast)
+ *
+ */
+ @Override
+ protected void onIntentionIdle()
+ {
+ // Set the AI Intention to AI_INTENTION_IDLE
+ changeIntention(AI_INTENTION_IDLE, null, null);
+
+ // Init cast and attack target
+ setCastTarget(null);
+ setAttackTarget(null);
+
+ // Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
+ clientStopMoving(null);
+
+ // Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
+ clientStopAutoAttack();
+
+ }
+
+ /**
+ * Manage the Active Intention : Stop Attack, Movement and Launch Think Event.
+ *
+ * Actions : if the Intention is not already Active
+ *
+ *
Set the AI Intention to AI_INTENTION_ACTIVE
Init cast and attack target
Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
Stop the actor movement server side AND client side by sending Server->Client packet
+ * StopMove/StopRotation (broadcast)
Launch the Think Event
+ *
+ */
+ @Override
+ protected void onIntentionActive()
+ {
+ // Check if the Intention is not already Active
+ if (getIntention() != AI_INTENTION_ACTIVE)
+ {
+ // Set the AI Intention to AI_INTENTION_ACTIVE
+ changeIntention(AI_INTENTION_ACTIVE, null, null);
+
+ // Init cast and attack target
+ setCastTarget(null);
+ setAttackTarget(null);
+
+ // Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
+ clientStopMoving(null);
+
+ // Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
+ clientStopAutoAttack();
+
+ // Also enable random animations for this L2Character if allowed
+ // This is only for mobs - town npcs are handled in their constructor
+ if (_actor instanceof L2Attackable)
+ {
+ ((L2Npc) _actor).startRandomAnimationTimer();
+ }
+
+ // Launch the Think Event
+ onEvtThink();
+ }
+ }
+
+ /**
+ * Manage the Rest Intention.
+ *
+ * Actions :
+ *
+ *
Set the AI Intention to AI_INTENTION_IDLE
+ *
+ */
+ @Override
+ protected void onIntentionRest()
+ {
+ // Set the AI Intention to AI_INTENTION_IDLE
+ setIntention(AI_INTENTION_IDLE);
+ }
+
+ /**
+ * Manage the Attack Intention : Stop current Attack (if necessary), Start a new Attack and Launch Think Event.
+ *
+ * Actions :
+ *
+ *
Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
Set the Intention of this AI to AI_INTENTION_ATTACK
Set or change the AI attack target
Start the actor Auto Attack client side by sending Server->Client packet
+ * AutoAttackStart (broadcast)
Launch the Think Event
+ *
+ * Overridden in :
+ *
+ *
L2AttackableAI : Calculate attack timeout
+ *
+ */
+ @Override
+ protected void onIntentionAttack(L2Character target)
+ {
+ if (target == null)
+ {
+ clientActionFailed();
+ return;
+ }
+
+ if (getIntention() == AI_INTENTION_REST)
+ {
+ // Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+ clientActionFailed();
+ return;
+ }
+
+ if (_actor.isAllSkillsDisabled() || _actor.isCastingNow() || _actor.isAfraid())
+ {
+ // Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+ clientActionFailed();
+ return;
+ }
+
+ // Check if the Intention is already AI_INTENTION_ATTACK
+ if (getIntention() == AI_INTENTION_ATTACK)
+ {
+ // Check if the AI already targets the L2Character
+ if (getAttackTarget() != target)
+ {
+ // Set the AI attack target (change target)
+ setAttackTarget(target);
+
+ stopFollow();
+
+ // Launch the Think Event
+ notifyEvent(CtrlEvent.EVT_THINK, null);
+
+ }
+ else
+ {
+ clientActionFailed(); // else client freezes until cancel target
+ }
+ }
+ else
+ {
+ // Set the Intention of this AbstractAI to AI_INTENTION_ATTACK
+ changeIntention(AI_INTENTION_ATTACK, target, null);
+
+ // Set the AI attack target
+ setAttackTarget(target);
+
+ stopFollow();
+
+ // Launch the Think Event
+ notifyEvent(CtrlEvent.EVT_THINK, null);
+ }
+ }
+
+ /**
+ * Manage the Cast Intention : Stop current Attack, Init the AI in order to cast and Launch Think Event.
+ *
+ * Actions :
+ *
+ *
Set the AI cast target
Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
Set the AI skill used by INTENTION_CAST
+ *
Set the Intention of this AI to AI_INTENTION_CAST
Launch the Think Event
+ *
+ */
+ @Override
+ protected void onIntentionCast(L2Skill skill, L2Object target)
+ {
+ if ((getIntention() == AI_INTENTION_REST) && skill.isMagic())
+ {
+ clientActionFailed();
+ _actor.setIsCastingNow(false);
+ return;
+ }
+
+ // Set the AI cast target
+ setCastTarget((L2Character) target);
+
+ // Stop actions client-side to cast the skill
+ if (skill.getHitTime() > 50)
+ {
+ // Abort the attack of the L2Character and send Server->Client ActionFailed packet
+ _actor.abortAttack();
+
+ // Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+ // no need for second ActionFailed packet, abortAttack() already sent it
+ // clientActionFailed();
+ }
+
+ // Set the AI skill used by INTENTION_CAST
+ _skill = skill;
+
+ // Change the Intention of this AbstractAI to AI_INTENTION_CAST
+ changeIntention(AI_INTENTION_CAST, skill, target);
+
+ // Launch the Think Event
+ notifyEvent(CtrlEvent.EVT_THINK, null);
+ }
+
+ /**
+ * Manage the Move To Intention : Stop current Attack and Launch a Move to Location Task.
+ *
+ * Actions :
+ *
+ *
Stop the actor auto-attack server side AND client side by sending Server->Client packet AutoAttackStop (broadcast)
Set the Intention of this AI to AI_INTENTION_MOVE_TO
Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet
+ * CharMoveToLocation (broadcast)
+ *
+ */
+ @Override
+ protected void onIntentionMoveTo(L2CharPosition pos)
+ {
+ if (getIntention() == AI_INTENTION_REST)
+ {
+ // Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+ clientActionFailed();
+ return;
+ }
+
+ if (_actor.isAllSkillsDisabled() || _actor.isCastingNow())
+ {
+ // Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+ clientActionFailed();
+ return;
+ }
+
+ // Set the Intention of this AbstractAI to AI_INTENTION_MOVE_TO
+ changeIntention(AI_INTENTION_MOVE_TO, pos, null);
+
+ // Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
+ clientStopAutoAttack();
+
+ // Abort the attack of the L2Character and send Server->Client ActionFailed packet
+ _actor.abortAttack();
+
+ // Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast)
+ moveTo(pos.x, pos.y, pos.z);
+ }
+
+ /**
+ * Manage the Follow Intention : Stop current Attack and Launch a Follow Task.
+ *
+ * Actions :
+ *
+ *
Stop the actor auto-attack server side AND client side by sending Server->Client packet AutoAttackStop (broadcast)
Set the Intention of this AI to AI_INTENTION_FOLLOW
Create and Launch an AI Follow Task to execute every 1s
+ *
+ */
+ @Override
+ protected void onIntentionFollow(L2Character target)
+ {
+ if (getIntention() == AI_INTENTION_REST)
+ {
+ // Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+ clientActionFailed();
+ return;
+ }
+
+ if (_actor.isAllSkillsDisabled() || _actor.isCastingNow())
+ {
+ // Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+ clientActionFailed();
+ return;
+ }
+
+ if (_actor.isMovementDisabled())
+ {
+ // Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+ clientActionFailed();
+ return;
+ }
+
+ // Dead actors can`t follow
+ if (_actor.isDead())
+ {
+ clientActionFailed();
+ return;
+ }
+
+ // do not follow yourself
+ if (_actor == target)
+ {
+ clientActionFailed();
+ return;
+ }
+
+ // Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
+ clientStopAutoAttack();
+
+ // Set the Intention of this AbstractAI to AI_INTENTION_FOLLOW
+ changeIntention(AI_INTENTION_FOLLOW, target, null);
+
+ // Create and Launch an AI Follow Task to execute every 1s
+ startFollow(target);
+ }
+
+ /**
+ * Manage the PickUp Intention : Set the pick up target and Launch a Move To Pawn Task (offset=20).
+ *
+ * Actions :
+ *
+ *
Set the AI pick up target
Set the Intention of this AI to AI_INTENTION_PICK_UP
Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn (broadcast)
+ *
+ */
+ @Override
+ protected void onIntentionPickUp(L2Object object)
+ {
+ if (getIntention() == AI_INTENTION_REST)
+ {
+ // Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+ clientActionFailed();
+ return;
+ }
+
+ if (_actor.isAllSkillsDisabled() || _actor.isCastingNow())
+ {
+ // Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+ clientActionFailed();
+ return;
+ }
+
+ // Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
+ clientStopAutoAttack();
+
+ if ((object instanceof L2ItemInstance) && (((L2ItemInstance) object).getLocation() != ItemLocation.VOID))
+ {
+ return;
+ }
+
+ // Set the Intention of this AbstractAI to AI_INTENTION_PICK_UP
+ changeIntention(AI_INTENTION_PICK_UP, object, null);
+
+ // Set the AI pick up target
+ setTarget(object);
+ if ((object.getX() == 0) && (object.getY() == 0)) // TODO: Find the drop&spawn bug
+ {
+ _log.warning("Object in coords 0,0 - using a temporary fix");
+ object.setXYZ(getActor().getX(), getActor().getY(), getActor().getZ() + 5);
+ }
+
+ // Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn (broadcast)
+ moveToPawn(object, 20);
+ }
+
+ /**
+ * Manage the Interact Intention : Set the interact target and Launch a Move To Pawn Task (offset=60).
+ *
+ * Actions :
+ *
+ *
Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
Set the AI interact target
Set the Intention of this AI to AI_INTENTION_INTERACT
Move the actor to Pawn server side AND client side by sending Server->Client
+ * packet MoveToPawn (broadcast)
+ *
+ */
+ @Override
+ protected void onIntentionInteract(L2Object object)
+ {
+ if (getIntention() == AI_INTENTION_REST)
+ {
+ // Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+ clientActionFailed();
+ return;
+ }
+
+ if (_actor.isAllSkillsDisabled() || _actor.isCastingNow())
+ {
+ // Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+ clientActionFailed();
+ return;
+ }
+
+ // Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
+ clientStopAutoAttack();
+
+ if (getIntention() != AI_INTENTION_INTERACT)
+ {
+ // Set the Intention of this AbstractAI to AI_INTENTION_INTERACT
+ changeIntention(AI_INTENTION_INTERACT, object, null);
+
+ // Set the AI interact target
+ setTarget(object);
+
+ // Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn (broadcast)
+ moveToPawn(object, 60);
+ }
+ }
+
+ /**
+ * Do nothing.
+ *
+ */
+ @Override
+ protected void onEvtThink()
+ {
+ // do nothing
+ }
+
+ /**
+ * Do nothing.
+ *
+ */
+ @Override
+ protected void onEvtAggression(L2Character target, int aggro)
+ {
+ // do nothing
+ }
+
+ /**
+ * Launch actions corresponding to the Event Stunned then onAttacked Event.
+ *
+ * Actions :
+ *
+ *
Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
Break an attack and send Server->Client ActionFailed
+ * packet and a System Message to the L2Character
Break a cast and send Server->Client ActionFailed packet and a System Message to the L2Character
Launch actions corresponding to the Event onAttacked (only for L2AttackableAI after the stunning periode)
+ *
+ */
+ @Override
+ protected void onEvtStunned(L2Character attacker)
+ {
+ // Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
+ _actor.broadcastPacket(new AutoAttackStop(_actor.getObjectId()));
+ if (AttackStanceTaskManager.getInstance().getAttackStanceTask(_actor))
+ {
+ AttackStanceTaskManager.getInstance().removeAttackStanceTask(_actor);
+ }
+
+ // Stop Server AutoAttack also
+ setAutoAttacking(false);
+
+ // Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
+ clientStopMoving(null);
+
+ // Launch actions corresponding to the Event onAttacked (only for L2AttackableAI after the stunning periode)
+ onEvtAttacked(attacker);
+ }
+
+ @Override
+ protected void onEvtParalyzed(L2Character attacker)
+ {
+ // Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
+ _actor.broadcastPacket(new AutoAttackStop(_actor.getObjectId()));
+ if (AttackStanceTaskManager.getInstance().getAttackStanceTask(_actor))
+ {
+ AttackStanceTaskManager.getInstance().removeAttackStanceTask(_actor);
+ }
+
+ // Stop Server AutoAttack also
+ setAutoAttacking(false);
+
+ // Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
+ clientStopMoving(null);
+
+ // Launch actions corresponding to the Event onAttacked (only for L2AttackableAI after the stunning periode)
+ onEvtAttacked(attacker);
+ }
+
+ /**
+ * Launch actions corresponding to the Event Sleeping.
+ *
+ * Actions :
+ *
+ *
Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
Break an attack and send Server->Client ActionFailed
+ * packet and a System Message to the L2Character
Break a cast and send Server->Client ActionFailed packet and a System Message to the L2Character
+ *
+ */
+ @Override
+ protected void onEvtSleeping(L2Character attacker)
+ {
+ // Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
+ _actor.broadcastPacket(new AutoAttackStop(_actor.getObjectId()));
+ if (AttackStanceTaskManager.getInstance().getAttackStanceTask(_actor))
+ {
+ AttackStanceTaskManager.getInstance().removeAttackStanceTask(_actor);
+ }
+
+ // stop Server AutoAttack also
+ setAutoAttacking(false);
+
+ // Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
+ clientStopMoving(null);
+ }
+
+ /**
+ * Launch actions corresponding to the Event Rooted.
+ *
+ * Actions :
+ *
+ *
Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
Launch actions corresponding to the Event onAttacked
+ *
+ */
+ @Override
+ protected void onEvtRooted(L2Character attacker)
+ {
+ // Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
+ // _actor.broadcastPacket(new AutoAttackStop(_actor.getObjectId()));
+ // if (AttackStanceTaskManager.getInstance().getAttackStanceTask(_actor))
+ // AttackStanceTaskManager.getInstance().removeAttackStanceTask(_actor);
+
+ // Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
+ clientStopMoving(null);
+
+ // Launch actions corresponding to the Event onAttacked
+ onEvtAttacked(attacker);
+
+ }
+
+ /**
+ * Launch actions corresponding to the Event Confused.
+ *
+ * Actions :
+ *
+ *
Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
Launch actions corresponding to the Event onAttacked
+ *
+ */
+ @Override
+ protected void onEvtConfused(L2Character attacker)
+ {
+ // Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
+ clientStopMoving(null);
+
+ // Launch actions corresponding to the Event onAttacked
+ onEvtAttacked(attacker);
+ }
+
+ /**
+ * Launch actions corresponding to the Event Muted.
+ *
+ * Actions :
+ *
+ *
Break a cast and send Server->Client ActionFailed packet and a System Message to the L2Character
+ *
+ */
+ @Override
+ protected void onEvtMuted(L2Character attacker)
+ {
+ // Break a cast and send Server->Client ActionFailed packet and a System Message to the L2Character
+ onEvtAttacked(attacker);
+ }
+
+ /**
+ * Do nothing.
+ *
+ */
+ @Override
+ protected void onEvtEvaded(L2Character attacker)
+ {
+ // do nothing
+ }
+
+ /**
+ * Launch actions corresponding to the Event ReadyToAct.
+ *
+ * Actions :
+ *
+ *
Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
If the Intention was AI_INTENTION_MOVE_TO, set the Intention to AI_INTENTION_ACTIVE
Launch actions corresponding to the Event Think
+ *
+ */
+ @Override
+ protected void onEvtArrivedBlocked(L2CharPosition blocked_at_pos)
+ {
+ // If the Intention was AI_INTENTION_MOVE_TO, set the Intention to AI_INTENTION_ACTIVE
+ if ((getIntention() == AI_INTENTION_MOVE_TO) || (getIntention() == AI_INTENTION_CAST))
+ {
+ setIntention(AI_INTENTION_ACTIVE);
+ }
+
+ // Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
+ clientStopMoving(blocked_at_pos);
+
+ /*
+ * if (Config.ACTIVATE_POSITION_RECORDER && Universe.getInstance().shouldLog(_accessor.getActor().getObjectId())) { if (!_accessor.getActor().isFlying()) Universe.getInstance().registerObstacle(blocked_at_pos.x, blocked_at_pos.y, blocked_at_pos.z); if (_accessor.getActor() instanceof
+ * L2PcInstance) ((L2PcInstance) _accessor.getActor()).explore(); }
+ */
+
+ // Launch actions corresponding to the Event Think
+ onEvtThink();
+ }
+
+ /**
+ * Launch actions corresponding to the Event ForgetObject.
+ *
+ * Actions :
+ *
+ *
If the object was targeted and the Intention was AI_INTENTION_INTERACT or AI_INTENTION_PICK_UP, set the Intention to AI_INTENTION_ACTIVE
If the object was targeted to attack, stop the auto-attack, cancel target and set the Intention to AI_INTENTION_ACTIVE
If the object
+ * was targeted to cast, cancel target and set the Intention to AI_INTENTION_ACTIVE
If the object was targeted to follow, stop the movement, cancel AI Follow Task and set the Intention to AI_INTENTION_ACTIVE
If the targeted object was the actor , cancel AI target, stop AI
+ * Follow Task, stop the movement and set the Intention to AI_INTENTION_IDLE
+ *
+ */
+ @Override
+ protected void onEvtForgetObject(L2Object object)
+ {
+ // If the object was targeted and the Intention was AI_INTENTION_INTERACT or AI_INTENTION_PICK_UP, set the Intention to AI_INTENTION_ACTIVE
+ if (getTarget() == object)
+ {
+ setTarget(null);
+
+ if (getIntention() == AI_INTENTION_INTERACT)
+ {
+ setIntention(AI_INTENTION_ACTIVE);
+ }
+ else if (getIntention() == AI_INTENTION_PICK_UP)
+ {
+ setIntention(AI_INTENTION_ACTIVE);
+ }
+ }
+
+ // Check if the object was targeted to attack
+ if (getAttackTarget() == object)
+ {
+ // Cancel attack target
+ setAttackTarget(null);
+
+ // Set the Intention of this AbstractAI to AI_INTENTION_ACTIVE
+ setIntention(AI_INTENTION_ACTIVE);
+ }
+
+ // Check if the object was targeted to cast
+ if (getCastTarget() == object)
+ {
+ // Cancel cast target
+ setCastTarget(null);
+
+ // Set the Intention of this AbstractAI to AI_INTENTION_ACTIVE
+ setIntention(AI_INTENTION_ACTIVE);
+ }
+
+ // Check if the object was targeted to follow
+ if (getFollowTarget() == object)
+ {
+ // Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
+ clientStopMoving(null);
+
+ // Stop an AI Follow Task
+ stopFollow();
+
+ // Set the Intention of this AbstractAI to AI_INTENTION_ACTIVE
+ setIntention(AI_INTENTION_ACTIVE);
+ }
+
+ // Check if the targeted object was the actor
+ if (_actor == object)
+ {
+ // Cancel AI target
+ setTarget(null);
+ setAttackTarget(null);
+ setCastTarget(null);
+
+ // Stop an AI Follow Task
+ stopFollow();
+
+ // Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
+ clientStopMoving(null);
+
+ // Set the Intention of this AbstractAI to AI_INTENTION_IDLE
+ changeIntention(AI_INTENTION_IDLE, null, null);
+ }
+ }
+
+ /**
+ * Launch actions corresponding to the Event Cancel.
+ *
+ * Actions :
+ *
+ *
Kill the actor client side by sending Server->Client packet AutoAttackStop, StopMove/StopRotation, Die (broadcast)
+ *
+ */
+ @Override
+ protected void onEvtDead()
+ {
+ // Stop an AI Tasks
+ stopAITask();
+
+ // Kill the actor client side by sending Server->Client packet AutoAttackStop, StopMove/StopRotation, Die (broadcast)
+ clientNotifyDead();
+
+ if (!(_actor instanceof L2Playable))
+ {
+ _actor.setWalking();
+ }
+ }
+
+ /**
+ * Launch actions corresponding to the Event Fake Death.
+ *
+ * Actions :
+ *
+ *
Stop an AI Follow Task
+ */
+ @Override
+ protected void onEvtFakeDeath()
+ {
+ // Stop an AI Follow Task
+ stopFollow();
+
+ // Stop the actor movement and send Server->Client packet StopMove/StopRotation (broadcast)
+ clientStopMoving(null);
+
+ // Init AI
+ _intention = AI_INTENTION_IDLE;
+ setTarget(null);
+ setCastTarget(null);
+ setAttackTarget(null);
+ }
+
+ /**
+ * Do nothing.
+ *
+ */
+ @Override
+ protected void onEvtFinishCasting()
+ {
+ // do nothing
+ }
+
+ protected boolean maybeMoveToPosition(Point3D worldPosition, int offset)
+ {
+ if (worldPosition == null)
+ {
+ _log.warning("maybeMoveToPosition: worldPosition == NULL!");
+ return false;
+ }
+
+ if (offset < 0)
+ {
+ return false; // skill radius -1
+ }
+
+ if (!_actor.isInsideRadius(worldPosition.getX(), worldPosition.getY(), offset + _actor.getTemplate().collisionRadius, false))
+ {
+ if (_actor.isMovementDisabled())
+ {
+ return true;
+ }
+
+ if (!_actor.isRunning() && !(this instanceof L2PlayerAI) && !(this instanceof L2SummonAI))
+ {
+ _actor.setRunning();
+ }
+
+ stopFollow();
+
+ int x = _actor.getX();
+ int y = _actor.getY();
+
+ double dx = worldPosition.getX() - x;
+ double dy = worldPosition.getY() - y;
+
+ double dist = Math.sqrt((dx * dx) + (dy * dy));
+
+ double sin = dy / dist;
+ double cos = dx / dist;
+
+ dist -= offset - 5;
+
+ x += (int) (dist * cos);
+ y += (int) (dist * sin);
+
+ moveTo(x, y, worldPosition.getZ());
+ return true;
+ }
+
+ if (getFollowTarget() != null)
+ {
+ stopFollow();
+ }
+
+ return false;
+ }
+
+ /**
+ * Manage the Move to Pawn action in function of the distance and of the Interact area.
+ *
+ * Actions :
+ *
+ *
Get the distance between the current position of the L2Character and the target (x,y)
If the distance > offset+20, move the actor (by running) to Pawn server side AND client side by sending Server->Client packet MoveToPawn (broadcast)
If the distance <= offset+20, Stop
+ * the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
+ *
+ * Example of use :
+ *
+ *
L2PLayerAI, L2SummonAI
+ *
+ * @param target The targeted L2Object
+ * @param offset The Interact area radius
+ * @return True if a movement must be done
+ */
+ protected boolean maybeMoveToPawn(L2Object target, int offset)
+ {
+ // Get the distance between the current position of the L2Character and the target (x,y)
+ if (target == null)
+ {
+ _log.warning("maybeMoveToPawn: target == NULL!");
+ return false;
+ }
+ if (offset < 0)
+ {
+ return false; // skill radius -1
+ }
+
+ offset += _actor.getTemplate().collisionRadius;
+ if (target instanceof L2Character)
+ {
+ offset += ((L2Character) target).getTemplate().collisionRadius;
+ }
+
+ if (!_actor.isInsideRadius(target, offset, false, false))
+ {
+ // Caller should be L2Playable and thinkAttack/thinkCast/thinkInteract/thinkPickUp
+ if (getFollowTarget() != null)
+ {
+
+ // allow larger hit range when the target is moving (check is run only once per second)
+ if (!_actor.isInsideRadius(target, offset + 100, false, false))
+ {
+ return true;
+ }
+ stopFollow();
+ return false;
+ }
+
+ if (_actor.isMovementDisabled())
+ {
+ // If player is trying attack target but he cannot move to attack target
+ // change his intention to idle
+ if (_actor.getAI().getIntention() == CtrlIntention.AI_INTENTION_ATTACK)
+ {
+ _actor.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE);
+ }
+
+ return true;
+ }
+
+ // while flying there is no move to cast
+ if ((_actor.getAI().getIntention() == CtrlIntention.AI_INTENTION_CAST) && (_actor instanceof L2PcInstance) && ((L2PcInstance) _actor).isTransformed())
+ {
+ if (!((L2PcInstance) _actor).getTransformation().canStartFollowToCast())
+ {
+ ((L2PcInstance) _actor).sendPacket(SystemMessage.getSystemMessage(SystemMessageId.DIST_TOO_FAR_CASTING_STOPPED));
+ ((L2PcInstance) _actor).sendPacket(ActionFailed.STATIC_PACKET);
+
+ return true;
+ }
+ }
+
+ // If not running, set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
+ if (!_actor.isRunning() && !(this instanceof L2PlayerAI) && !(this instanceof L2SummonAI))
+ {
+ _actor.setRunning();
+ }
+
+ stopFollow();
+ if ((target instanceof L2Character) && !(target instanceof L2DoorInstance))
+ {
+ if (((L2Character) target).isMoving())
+ {
+ offset -= 100;
+ }
+ if (offset < 5)
+ {
+ offset = 5;
+ }
+
+ startFollow((L2Character) target, offset);
+ }
+ else
+ {
+ // Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn (broadcast)
+ moveToPawn(target, offset);
+ }
+ return true;
+ }
+
+ if (getFollowTarget() != null)
+ {
+ stopFollow();
+ }
+
+ // Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
+ // clientStopMoving(null);
+ return false;
+ }
+
+ /**
+ * Modify current Intention and actions if the target is lost or dead.
+ *
+ * Actions : If the target is lost or dead
+ *
+ *
Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
Set the Intention of this AbstractAI to
+ * AI_INTENTION_ACTIVE
+ *
+ * Example of use :
+ *
+ *
L2PLayerAI, L2SummonAI
+ *
+ * @param target The targeted L2Object
+ * @return True if the target is lost or dead (false if fakedeath)
+ */
+ protected boolean checkTargetLostOrDead(L2Character target)
+ {
+ if ((target == null) || target.isAlikeDead())
+ {
+ // check if player is fakedeath
+ if ((target instanceof L2PcInstance) && ((L2PcInstance) target).isFakeDeath())
+ {
+ target.stopFakeDeath(true);
+ return false;
+ }
+
+ // Set the Intention of this AbstractAI to AI_INTENTION_ACTIVE
+ setIntention(AI_INTENTION_ACTIVE);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Modify current Intention and actions if the target is lost.
+ *
+ * Actions : If the target is lost
+ *
+ *
Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation (broadcast)
Set the Intention of this AbstractAI to
+ * AI_INTENTION_ACTIVE
+ *
+ * Example of use :
+ *
+ *
L2PLayerAI, L2SummonAI
+ *
+ * @param target The targeted L2Object
+ * @return True if the target is lost
+ */
+ protected boolean checkTargetLost(L2Object target)
+ {
+ // check if player is fakedeath
+ if (target instanceof L2PcInstance)
+ {
+ L2PcInstance target2 = (L2PcInstance) target; // convert object to chara
+
+ if (target2.isFakeDeath())
+ {
+ target2.stopFakeDeath(true);
+ return false;
+ }
+ }
+ if (target == null)
+ {
+ // Set the Intention of this AbstractAI to AI_INTENTION_ACTIVE
+ setIntention(AI_INTENTION_ACTIVE);
+ return true;
+ }
+ if ((_actor != null) && (_skill != null) && _skill.isOffensive() && (_skill.getSkillRadius() > 0) && (Config.GEODATA > 0) && !GeoData.getInstance().canSeeTarget(_actor, target))
+ {
+ setIntention(AI_INTENTION_ACTIVE);
+ return true;
+ }
+ return false;
+ }
+
+ protected class SelfAnalysis
+ {
+ public boolean isMage = false;
+ public boolean isBalanced;
+ public boolean isArcher = false;
+ public boolean isHealer = false;
+ public boolean isFighter = false;
+ public boolean cannotMoveOnLand = false;
+ public List generalSkills = new FastList<>();
+ public List buffSkills = new FastList<>();
+ public int lastBuffTick = 0;
+ public List debuffSkills = new FastList<>();
+ public int lastDebuffTick = 0;
+ public List cancelSkills = new FastList<>();
+ public List healSkills = new FastList<>();
+ // public List trickSkills = new FastList();
+ public List generalDisablers = new FastList<>();
+ public List sleepSkills = new FastList<>();
+ public List rootSkills = new FastList<>();
+ public List muteSkills = new FastList<>();
+ public List resurrectSkills = new FastList<>();
+ public boolean hasHealOrResurrect = false;
+ public boolean hasLongRangeSkills = false;
+ public boolean hasLongRangeDamageSkills = false;
+ public int maxCastRange = 0;
+
+ public SelfAnalysis()
+ {
+ }
+
+ public void init()
+ {
+ switch (((L2NpcTemplate) _actor.getTemplate()).getAIDataStatic().getAiType())
+ {
+ case FIGHTER:
+ isFighter = true;
+ break;
+ case MAGE:
+ isMage = true;
+ break;
+ case CORPSE:
+ case BALANCED:
+ isBalanced = true;
+ break;
+ case ARCHER:
+ isArcher = true;
+ break;
+ case HEALER:
+ isHealer = true;
+ break;
+ default:
+ isFighter = true;
+ break;
+ }
+ // water movement analysis
+ if (_actor instanceof L2Npc)
+ {
+ int npcId = ((L2Npc) _actor).getNpcId();
+
+ switch (npcId)
+ {
+ case 20314: // great white shark
+ case 20849: // Light Worm
+ cannotMoveOnLand = true;
+ break;
+ default:
+ cannotMoveOnLand = false;
+ break;
+ }
+ }
+ // skill analysis
+ for (L2Skill sk : _actor.getAllSkills())
+ {
+ if (sk.isPassive())
+ {
+ continue;
+ }
+ int castRange = sk.getCastRange();
+ boolean hasLongRangeDamageSkill = false;
+ switch (sk.getSkillType())
+ {
+ case HEAL:
+ case HEAL_PERCENT:
+ case HEAL_STATIC:
+ case BALANCE_LIFE:
+ case HOT:
+ healSkills.add(sk);
+ hasHealOrResurrect = true;
+ continue; // won't be considered something for fighting
+ case BUFF:
+ buffSkills.add(sk);
+ continue; // won't be considered something for fighting
+ case PARALYZE:
+ case STUN:
+ // hardcoding petrification until improvements are made to
+ // EffectTemplate... petrification is totally different for
+ // AI than paralyze
+ switch (sk.getId())
+ {
+ case 367:
+ case 4111:
+ case 4383:
+ case 4616:
+ case 4578:
+ sleepSkills.add(sk);
+ break;
+ default:
+ generalDisablers.add(sk);
+ break;
+ }
+ break;
+ case MUTE:
+ muteSkills.add(sk);
+ break;
+ case SLEEP:
+ sleepSkills.add(sk);
+ break;
+ case ROOT:
+ rootSkills.add(sk);
+ break;
+ case FEAR: // could be used as an alternative for healing?
+ case CONFUSION:
+ // trickSkills.add(sk);
+ case DEBUFF:
+ debuffSkills.add(sk);
+ break;
+ case CANCEL:
+ case NEGATE:
+ cancelSkills.add(sk);
+ break;
+ case RESURRECT:
+ resurrectSkills.add(sk);
+ hasHealOrResurrect = true;
+ break;
+ case NOTDONE:
+ case COREDONE:
+ continue; // won't be considered something for fighting
+ default:
+ generalSkills.add(sk);
+ hasLongRangeDamageSkill = true;
+ break;
+ }
+ if (castRange > 70)
+ {
+ hasLongRangeSkills = true;
+ if (hasLongRangeDamageSkill)
+ {
+ hasLongRangeDamageSkills = true;
+ }
+ }
+ if (castRange > maxCastRange)
+ {
+ maxCastRange = castRange;
+ }
+
+ }
+ // Because of missing skills, some mages/balanced cannot play like mages
+ if (!hasLongRangeDamageSkills && isMage)
+ {
+ isBalanced = true;
+ isMage = false;
+ isFighter = false;
+ }
+ if (!hasLongRangeSkills && (isMage || isBalanced))
+ {
+ isBalanced = false;
+ isMage = false;
+ isFighter = true;
+ }
+ if (generalSkills.isEmpty() && isMage)
+ {
+ isBalanced = true;
+ isMage = false;
+ }
+ }
+ }
+
+ protected class TargetAnalysis
+ {
+ public L2Character character;
+ public boolean isMage;
+ public boolean isBalanced;
+ public boolean isArcher;
+ public boolean isFighter;
+ public boolean isCanceled;
+ public boolean isSlower;
+ public boolean isMagicResistant;
+
+ public TargetAnalysis()
+ {
+ }
+
+ public void update(L2Character target)
+ {
+ // update status once in 4 seconds
+ if ((target == character) && (Rnd.nextInt(100) > 25))
+ {
+ return;
+ }
+ character = target;
+ if (target == null)
+ {
+ return;
+ }
+ isMage = false;
+ isBalanced = false;
+ isArcher = false;
+ isFighter = false;
+ isCanceled = false;
+
+ if (target.getMAtk(null, null) > (1.5 * target.getPAtk(null)))
+ {
+ isMage = true;
+ }
+ else if (((target.getPAtk(null) * 0.8) < target.getMAtk(null, null)) || ((target.getMAtk(null, null) * 0.8) > target.getPAtk(null)))
+ {
+ isBalanced = true;
+ }
+ else
+ {
+ L2Weapon weapon = target.getActiveWeaponItem();
+ if ((weapon != null) && ((weapon.getItemType() == L2WeaponType.BOW) || (weapon.getItemType() == L2WeaponType.CROSSBOW)))
+ {
+ isArcher = true;
+ }
+ else
+ {
+ isFighter = true;
+ }
+ }
+ if (target.getRunSpeed() < (_actor.getRunSpeed() - 3))
+ {
+ isSlower = true;
+ }
+ else
+ {
+ isSlower = false;
+ }
+ if ((target.getMDef(null, null) * 1.2) > _actor.getMAtk(null, null))
+ {
+ isMagicResistant = true;
+ }
+ else
+ {
+ isMagicResistant = false;
+ }
+ if (target.getBuffCount() < 4)
+ {
+ isCanceled = true;
+ }
+ }
+ }
+
+ public boolean canAura(L2Skill sk)
+ {
+ if ((sk.getTargetType() == L2Skill.SkillTargetType.TARGET_AURA) || (sk.getTargetType() == L2Skill.SkillTargetType.TARGET_BEHIND_AURA) || (sk.getTargetType() == L2Skill.SkillTargetType.TARGET_FRONT_AURA))
+ {
+ for (L2Object target : _actor.getKnownList().getKnownCharactersInRadius(sk.getSkillRadius()))
+ {
+ if (target == getAttackTarget())
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean canAOE(L2Skill sk)
+ {
+ if ((sk.getSkillType() != L2SkillType.NEGATE) || (sk.getSkillType() != L2SkillType.CANCEL))
+ {
+ if ((sk.getTargetType() == L2Skill.SkillTargetType.TARGET_AURA) || (sk.getTargetType() == L2Skill.SkillTargetType.TARGET_BEHIND_AURA) || (sk.getTargetType() == L2Skill.SkillTargetType.TARGET_FRONT_AURA))
+ {
+ boolean cancast = true;
+ for (L2Character target : _actor.getKnownList().getKnownCharactersInRadius(sk.getSkillRadius()))
+ {
+ if (!GeoData.getInstance().canSeeTarget(_actor, target))
+ {
+ continue;
+ }
+ if (target instanceof L2Attackable)
+ {
+ L2Npc targets = ((L2Npc) target);
+ L2Npc actors = ((L2Npc) _actor);
+
+ if ((targets.getEnemyClan() == null) || (actors.getClan() == null) || !targets.getEnemyClan().equals(actors.getClan()) || ((actors.getClan() == null) && (actors.getIsChaos() == 0)))
+ {
+ continue;
+ }
+ }
+ L2Effect[] effects = target.getAllEffects();
+ for (int i = 0; (effects != null) && (i < effects.length); i++)
+ {
+ L2Effect effect = effects[i];
+ if (effect.getSkill() == sk)
+ {
+ cancast = false;
+ break;
+ }
+ }
+ }
+ if (cancast)
+ {
+ return true;
+ }
+ }
+ else if ((sk.getTargetType() == L2Skill.SkillTargetType.TARGET_AREA) || (sk.getTargetType() == L2Skill.SkillTargetType.TARGET_BEHIND_AREA) || (sk.getTargetType() == L2Skill.SkillTargetType.TARGET_FRONT_AREA))
+ {
+ boolean cancast = true;
+ for (L2Character target : getAttackTarget().getKnownList().getKnownCharactersInRadius(sk.getSkillRadius()))
+ {
+ if (!GeoData.getInstance().canSeeTarget(_actor, target) || (target == null))
+ {
+ continue;
+ }
+ if (target instanceof L2Attackable)
+ {
+ L2Npc targets = ((L2Npc) target);
+ L2Npc actors = ((L2Npc) _actor);
+ if ((targets.getEnemyClan() == null) || (actors.getClan() == null) || !targets.getEnemyClan().equals(actors.getClan()) || ((actors.getClan() == null) && (actors.getIsChaos() == 0)))
+ {
+ continue;
+ }
+ }
+ L2Effect[] effects = target.getAllEffects();
+ if (effects.length > 0)
+ {
+ cancast = true;
+ }
+ }
+ if (cancast)
+ {
+ return true;
+ }
+ }
+ }
+ else
+ {
+ if ((sk.getTargetType() == L2Skill.SkillTargetType.TARGET_AURA) || (sk.getTargetType() == L2Skill.SkillTargetType.TARGET_BEHIND_AURA) || (sk.getTargetType() == L2Skill.SkillTargetType.TARGET_FRONT_AURA))
+ {
+ boolean cancast = false;
+ for (L2Character target : _actor.getKnownList().getKnownCharactersInRadius(sk.getSkillRadius()))
+ {
+ if (!GeoData.getInstance().canSeeTarget(_actor, target))
+ {
+ continue;
+ }
+ if (target instanceof L2Attackable)
+ {
+ L2Npc targets = ((L2Npc) target);
+ L2Npc actors = ((L2Npc) _actor);
+ if ((targets.getEnemyClan() == null) || (actors.getClan() == null) || !targets.getEnemyClan().equals(actors.getClan()) || ((actors.getClan() == null) && (actors.getIsChaos() == 0)))
+ {
+ continue;
+ }
+ }
+ L2Effect[] effects = target.getAllEffects();
+ if (effects.length > 0)
+ {
+ cancast = true;
+ }
+ }
+ if (cancast)
+ {
+ return true;
+ }
+ }
+ else if ((sk.getTargetType() == L2Skill.SkillTargetType.TARGET_AREA) || (sk.getTargetType() == L2Skill.SkillTargetType.TARGET_BEHIND_AREA) || (sk.getTargetType() == L2Skill.SkillTargetType.TARGET_FRONT_AREA))
+ {
+ boolean cancast = true;
+ for (L2Character target : getAttackTarget().getKnownList().getKnownCharactersInRadius(sk.getSkillRadius()))
+ {
+ if (!GeoData.getInstance().canSeeTarget(_actor, target))
+ {
+ continue;
+ }
+ if (target instanceof L2Attackable)
+ {
+ L2Npc targets = ((L2Npc) target);
+ L2Npc actors = ((L2Npc) _actor);
+ if ((targets.getEnemyClan() == null) || (actors.getClan() == null) || !targets.getEnemyClan().equals(actors.getClan()) || ((actors.getClan() == null) && (actors.getIsChaos() == 0)))
+ {
+ continue;
+ }
+ }
+ L2Effect[] effects = target.getAllEffects();
+ for (int i = 0; (effects != null) && (i < effects.length); i++)
+ {
+ L2Effect effect = effects[i];
+ if (effect.getSkill() == sk)
+ {
+ cancast = false;
+ break;
+ }
+ }
+ }
+ if (cancast)
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean canParty(L2Skill sk)
+ {
+ if (sk.getTargetType() == L2Skill.SkillTargetType.TARGET_PARTY)
+ {
+ int count = 0;
+ int ccount = 0;
+ for (L2Character target : _actor.getKnownList().getKnownCharactersInRadius(sk.getSkillRadius()))
+ {
+ if (!(target instanceof L2Attackable) || !GeoData.getInstance().canSeeTarget(_actor, target))
+ {
+ continue;
+ }
+ L2Npc targets = ((L2Npc) target);
+ L2Npc actors = ((L2Npc) _actor);
+ if ((actors.getFactionId() != null) && targets.getFactionId().equals(actors.getFactionId()))
+ {
+ count++;
+ L2Effect[] effects = target.getAllEffects();
+ for (int i = 0; (effects != null) && (i < effects.length); i++)
+ {
+
+ L2Effect effect = effects[i];
+ if (effect.getSkill() == sk)
+ {
+ ccount++;
+ break;
+ }
+ }
+ }
+ }
+ if (ccount < count)
+ {
+ return true;
+ }
+
+ }
+ return false;
+ }
+
+ public boolean isParty(L2Skill sk)
+ {
+ if (sk.getTargetType() == L2Skill.SkillTargetType.TARGET_PARTY)
+ {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/ai/L2ControllableMobAI.java b/L2J_Server/java/com/l2jserver/gameserver/ai/L2ControllableMobAI.java
new file mode 100644
index 00000000..5dc8fca3
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/ai/L2ControllableMobAI.java
@@ -0,0 +1,589 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.ai;
+
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
+
+import java.util.Collection;
+import java.util.List;
+
+import javolution.util.FastList;
+
+import com.l2jserver.gameserver.model.L2Object;
+import com.l2jserver.gameserver.model.L2Skill;
+import com.l2jserver.gameserver.model.MobGroup;
+import com.l2jserver.gameserver.model.MobGroupTable;
+import com.l2jserver.gameserver.model.actor.L2Attackable;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.actor.L2Character.AIAccessor;
+import com.l2jserver.gameserver.model.actor.L2Npc;
+import com.l2jserver.gameserver.model.actor.L2Playable;
+import com.l2jserver.gameserver.model.actor.instance.L2ControllableMobInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2NpcInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.util.Util;
+import com.l2jserver.util.Rnd;
+
+/**
+ * @author littlecrow AI for controllable mobs
+ */
+public class L2ControllableMobAI extends L2AttackableAI
+{
+ public static final int AI_IDLE = 1;
+ public static final int AI_NORMAL = 2;
+ public static final int AI_FORCEATTACK = 3;
+ public static final int AI_FOLLOW = 4;
+ public static final int AI_CAST = 5;
+ public static final int AI_ATTACK_GROUP = 6;
+
+ private int _alternateAI;
+
+ private boolean _isThinking; // to prevent thinking recursively
+ private boolean _isNotMoving;
+
+ private L2Character _forcedTarget;
+ private MobGroup _targetGroup;
+
+ protected void thinkFollow()
+ {
+ L2Attackable me = (L2Attackable) _actor;
+
+ if (!Util.checkIfInRange(MobGroupTable.FOLLOW_RANGE, me, getForcedTarget(), true))
+ {
+ int signX = (Rnd.nextInt(2) == 0) ? -1 : 1;
+ int signY = (Rnd.nextInt(2) == 0) ? -1 : 1;
+ int randX = Rnd.nextInt(MobGroupTable.FOLLOW_RANGE);
+ int randY = Rnd.nextInt(MobGroupTable.FOLLOW_RANGE);
+
+ moveTo(getForcedTarget().getX() + (signX * randX), getForcedTarget().getY() + (signY * randY), getForcedTarget().getZ());
+ }
+ }
+
+ @Override
+ protected void onEvtThink()
+ {
+ if (isThinking())
+ {
+ return;
+ }
+
+ setThinking(true);
+
+ try
+ {
+ switch (getAlternateAI())
+ {
+ case AI_IDLE:
+ if (getIntention() != CtrlIntention.AI_INTENTION_ACTIVE)
+ {
+ setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
+ }
+ break;
+ case AI_FOLLOW:
+ thinkFollow();
+ break;
+ case AI_CAST:
+ thinkCast();
+ break;
+ case AI_FORCEATTACK:
+ thinkForceAttack();
+ break;
+ case AI_ATTACK_GROUP:
+ thinkAttackGroup();
+ break;
+ default:
+ if (getIntention() == AI_INTENTION_ACTIVE)
+ {
+ thinkActive();
+ }
+ else if (getIntention() == AI_INTENTION_ATTACK)
+ {
+ thinkAttack();
+ }
+ break;
+ }
+ }
+ finally
+ {
+ setThinking(false);
+ }
+ }
+
+ protected void thinkCast()
+ {
+ L2Attackable npc = (L2Attackable) _actor;
+
+ if ((getAttackTarget() == null) || getAttackTarget().isAlikeDead())
+ {
+ setAttackTarget(findNextRndTarget());
+ clientStopMoving(null);
+ }
+
+ if (getAttackTarget() == null)
+ {
+ return;
+ }
+
+ npc.setTarget(getAttackTarget());
+
+ L2Skill[] skills = _actor.getAllSkills();
+
+ if (!_actor.isMuted())
+ {
+ int max_range = 0;
+ // check distant skills
+
+ for (L2Skill sk : skills)
+ {
+ if (Util.checkIfInRange(sk.getCastRange(), _actor, getAttackTarget(), true) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() > _actor.getStat().getMpConsume(sk)))
+ {
+ _accessor.doCast(sk);
+ return;
+ }
+
+ max_range = Math.max(max_range, sk.getCastRange());
+ }
+
+ if (!isNotMoving())
+ {
+ moveToPawn(getAttackTarget(), max_range);
+ }
+
+ return;
+ }
+ }
+
+ protected void thinkAttackGroup()
+ {
+ L2Character target = getForcedTarget();
+ if ((target == null) || target.isAlikeDead())
+ {
+ // try to get next group target
+ setForcedTarget(findNextGroupTarget());
+ clientStopMoving(null);
+ }
+
+ if (target == null)
+ {
+ return;
+ }
+
+ _actor.setTarget(target);
+ L2Skill[] skills = _actor.getAllSkills();
+ double dist2 = _actor.getPlanDistanceSq(target.getX(), target.getY());
+ int range = _actor.getPhysicalAttackRange() + _actor.getTemplate().collisionRadius + target.getTemplate().collisionRadius;
+ int max_range = range;
+
+ // as a response, we put the target in a forcedattack mode
+ L2ControllableMobInstance theTarget = (L2ControllableMobInstance) target;
+ L2ControllableMobAI ctrlAi = (L2ControllableMobAI) theTarget.getAI();
+ ctrlAi.forceAttack(_actor);
+
+ if (!_actor.isMuted() && (dist2 > ((range + 20) * (range + 20))))
+ {
+ // check distant skills
+ for (L2Skill sk : skills)
+ {
+ int castRange = sk.getCastRange();
+
+ if (((castRange * castRange) >= dist2) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() > _actor.getStat().getMpConsume(sk)))
+ {
+ _accessor.doCast(sk);
+ return;
+ }
+
+ max_range = Math.max(max_range, castRange);
+ }
+
+ if (!isNotMoving())
+ {
+ moveToPawn(target, range);
+ }
+
+ return;
+ }
+ _accessor.doAttack(target);
+ }
+
+ protected void thinkForceAttack()
+ {
+ if ((getForcedTarget() == null) || getForcedTarget().isAlikeDead())
+ {
+ clientStopMoving(null);
+ setIntention(AI_INTENTION_ACTIVE);
+ setAlternateAI(AI_IDLE);
+ }
+
+ _actor.setTarget(getForcedTarget());
+ L2Skill[] skills = _actor.getAllSkills();
+ double dist2 = _actor.getPlanDistanceSq(getForcedTarget().getX(), getForcedTarget().getY());
+ int range = _actor.getPhysicalAttackRange() + _actor.getTemplate().collisionRadius + getForcedTarget().getTemplate().collisionRadius;
+ int max_range = range;
+
+ if (!_actor.isMuted() && (dist2 > ((range + 20) * (range + 20))))
+ {
+ // check distant skills
+ for (L2Skill sk : skills)
+ {
+ int castRange = sk.getCastRange();
+
+ if (((castRange * castRange) >= dist2) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() > _actor.getStat().getMpConsume(sk)))
+ {
+ _accessor.doCast(sk);
+ return;
+ }
+
+ max_range = Math.max(max_range, castRange);
+ }
+
+ if (!isNotMoving())
+ {
+ moveToPawn(getForcedTarget(), _actor.getPhysicalAttackRange()/* range */);
+ }
+
+ return;
+ }
+
+ _accessor.doAttack(getForcedTarget());
+ }
+
+ protected void thinkAttack()
+ {
+ if ((getAttackTarget() == null) || getAttackTarget().isAlikeDead())
+ {
+ if (getAttackTarget() != null)
+ {
+ // stop hating
+ L2Attackable npc = (L2Attackable) _actor;
+ npc.stopHating(getAttackTarget());
+ }
+
+ setIntention(AI_INTENTION_ACTIVE);
+ }
+ else
+ {
+ // notify aggression
+ if (((L2Npc) _actor).getFactionId() != null)
+ {
+ String faction_id = ((L2Npc) _actor).getFactionId();
+
+ Collection objs = _actor.getKnownList().getKnownObjects().values();
+ // synchronized (_actor.getKnownList().getKnownObjects())
+ {
+ for (L2Object obj : objs)
+ {
+ if (!(obj instanceof L2Npc))
+ {
+ continue;
+ }
+
+ L2Npc npc = (L2Npc) obj;
+
+ if (!faction_id.equals(npc.getFactionId()))
+ {
+ continue;
+ }
+
+ if (_actor.isInsideRadius(npc, npc.getFactionRange(), false, true) && (Math.abs(getAttackTarget().getZ() - npc.getZ()) < 200))
+ {
+ npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, getAttackTarget(), 1);
+ }
+ }
+ }
+ }
+
+ _actor.setTarget(getAttackTarget());
+ L2Skill[] skills = _actor.getAllSkills();
+ double dist2 = _actor.getPlanDistanceSq(getAttackTarget().getX(), getAttackTarget().getY());
+ int range = _actor.getPhysicalAttackRange() + _actor.getTemplate().collisionRadius + getAttackTarget().getTemplate().collisionRadius;
+ int max_range = range;
+
+ if (!_actor.isMuted() && (dist2 > ((range + 20) * (range + 20))))
+ {
+ // check distant skills
+ for (L2Skill sk : skills)
+ {
+ int castRange = sk.getCastRange();
+
+ if (((castRange * castRange) >= dist2) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() > _actor.getStat().getMpConsume(sk)))
+ {
+ _accessor.doCast(sk);
+ return;
+ }
+
+ max_range = Math.max(max_range, castRange);
+ }
+
+ moveToPawn(getAttackTarget(), range);
+ return;
+ }
+
+ // Force mobs to attack anybody if confused.
+ L2Character hated;
+
+ if (_actor.isConfused())
+ {
+ hated = findNextRndTarget();
+ }
+ else
+ {
+ hated = getAttackTarget();
+ }
+
+ if (hated == null)
+ {
+ setIntention(AI_INTENTION_ACTIVE);
+ return;
+ }
+
+ if (hated != getAttackTarget())
+ {
+ setAttackTarget(hated);
+ }
+
+ if (!_actor.isMuted() && (skills.length > 0) && (Rnd.nextInt(5) == 3))
+ {
+ for (L2Skill sk : skills)
+ {
+ int castRange = sk.getCastRange();
+
+ if (((castRange * castRange) >= dist2) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)))
+ {
+ _accessor.doCast(sk);
+ return;
+ }
+ }
+ }
+
+ _accessor.doAttack(getAttackTarget());
+ }
+ }
+
+ private void thinkActive()
+ {
+ setAttackTarget(findNextRndTarget());
+ L2Character hated;
+
+ if (_actor.isConfused())
+ {
+ hated = findNextRndTarget();
+ }
+ else
+ {
+ hated = getAttackTarget();
+ }
+
+ if (hated != null)
+ {
+ _actor.setRunning();
+ setIntention(CtrlIntention.AI_INTENTION_ATTACK, hated);
+ }
+ }
+
+ private boolean autoAttackCondition(L2Character target)
+ {
+ if ((target == null) || !(_actor instanceof L2Attackable))
+ {
+ return false;
+ }
+ L2Attackable me = (L2Attackable) _actor;
+
+ if ((target instanceof L2NpcInstance) || (target instanceof L2DoorInstance))
+ {
+ return false;
+ }
+
+ if (target.isAlikeDead() || !me.isInsideRadius(target, me.getAggroRange(), false, false) || (Math.abs(_actor.getZ() - target.getZ()) > 100))
+ {
+ return false;
+ }
+
+ // Check if the target isn't invulnerable
+ if (target.isInvul())
+ {
+ return false;
+ }
+
+ // Spawn protection (only against mobs)
+ if ((target instanceof L2PcInstance) && ((L2PcInstance) target).isSpawnProtected())
+ {
+ return false;
+ }
+
+ // Check if the target is a L2PlayableInstance
+ if (target instanceof L2Playable)
+ {
+ // Check if the target isn't in silent move mode
+ if (((L2Playable) target).isSilentMoving())
+ {
+ return false;
+ }
+ }
+
+ if (target instanceof L2Npc)
+ {
+ return false;
+ }
+
+ return me.isAggressive();
+ }
+
+ private L2Character findNextRndTarget()
+ {
+ int aggroRange = ((L2Attackable) _actor).getAggroRange();
+ L2Attackable npc = (L2Attackable) _actor;
+ int npcX, npcY, targetX, targetY;
+ double dy, dx;
+ double dblAggroRange = aggroRange * aggroRange;
+
+ List potentialTarget = new FastList<>();
+
+ Collection objs = npc.getKnownList().getKnownObjects().values();
+ // synchronized (npc.getKnownList().getKnownObjects())
+ {
+ for (L2Object obj : objs)
+ {
+ if (!(obj instanceof L2Character))
+ {
+ continue;
+ }
+
+ npcX = npc.getX();
+ npcY = npc.getY();
+ targetX = obj.getX();
+ targetY = obj.getY();
+
+ dx = npcX - targetX;
+ dy = npcY - targetY;
+
+ if (((dx * dx) + (dy * dy)) > dblAggroRange)
+ {
+ continue;
+ }
+
+ L2Character target = (L2Character) obj;
+
+ if (autoAttackCondition(target))
+ {
+ potentialTarget.add(target);
+ }
+ }
+ }
+
+ if (potentialTarget.isEmpty())
+ {
+ return null;
+ }
+
+ // we choose a random target
+ int choice = Rnd.nextInt(potentialTarget.size());
+ L2Character target = potentialTarget.get(choice);
+
+ return target;
+ }
+
+ private L2ControllableMobInstance findNextGroupTarget()
+ {
+ return getGroupTarget().getRandomMob();
+ }
+
+ public L2ControllableMobAI(AIAccessor accessor)
+ {
+ super(accessor);
+ setAlternateAI(AI_IDLE);
+ }
+
+ public int getAlternateAI()
+ {
+ return _alternateAI;
+ }
+
+ public void setAlternateAI(int _alternateai)
+ {
+ _alternateAI = _alternateai;
+ }
+
+ public void forceAttack(L2Character target)
+ {
+ setAlternateAI(AI_FORCEATTACK);
+ setForcedTarget(target);
+ }
+
+ public void forceAttackGroup(MobGroup group)
+ {
+ setForcedTarget(null);
+ setGroupTarget(group);
+ setAlternateAI(AI_ATTACK_GROUP);
+ }
+
+ public void stop()
+ {
+ setAlternateAI(AI_IDLE);
+ clientStopMoving(null);
+ }
+
+ public void move(int x, int y, int z)
+ {
+ moveTo(x, y, z);
+ }
+
+ public void follow(L2Character target)
+ {
+ setAlternateAI(AI_FOLLOW);
+ setForcedTarget(target);
+ }
+
+ public boolean isThinking()
+ {
+ return _isThinking;
+ }
+
+ public boolean isNotMoving()
+ {
+ return _isNotMoving;
+ }
+
+ public void setNotMoving(boolean isNotMoving)
+ {
+ _isNotMoving = isNotMoving;
+ }
+
+ public void setThinking(boolean isThinking)
+ {
+ _isThinking = isThinking;
+ }
+
+ private L2Character getForcedTarget()
+ {
+ return _forcedTarget;
+ }
+
+ private MobGroup getGroupTarget()
+ {
+ return _targetGroup;
+ }
+
+ private void setForcedTarget(L2Character forcedTarget)
+ {
+ _forcedTarget = forcedTarget;
+ }
+
+ private void setGroupTarget(MobGroup targetGroup)
+ {
+ _targetGroup = targetGroup;
+ }
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/ai/L2DoorAI.java b/L2J_Server/java/com/l2jserver/gameserver/ai/L2DoorAI.java
new file mode 100644
index 00000000..bc8d19bf
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/ai/L2DoorAI.java
@@ -0,0 +1,182 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.ai;
+
+import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.model.L2CharPosition;
+import com.l2jserver.gameserver.model.L2Object;
+import com.l2jserver.gameserver.model.L2Skill;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.actor.instance.L2DefenderInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance;
+
+/**
+ * @author mkizub
+ */
+public class L2DoorAI extends L2CharacterAI
+{
+
+ public L2DoorAI(L2DoorInstance.AIAccessor accessor)
+ {
+ super(accessor);
+ }
+
+ // rather stupid AI... well, it's for doors :D
+ @Override
+ protected void onIntentionIdle()
+ {
+ }
+
+ @Override
+ protected void onIntentionActive()
+ {
+ }
+
+ @Override
+ protected void onIntentionRest()
+ {
+ }
+
+ @Override
+ protected void onIntentionAttack(L2Character target)
+ {
+ }
+
+ @Override
+ protected void onIntentionCast(L2Skill skill, L2Object target)
+ {
+ }
+
+ @Override
+ protected void onIntentionMoveTo(L2CharPosition destination)
+ {
+ }
+
+ @Override
+ protected void onIntentionFollow(L2Character target)
+ {
+ }
+
+ @Override
+ protected void onIntentionPickUp(L2Object item)
+ {
+ }
+
+ @Override
+ protected void onIntentionInteract(L2Object object)
+ {
+ }
+
+ @Override
+ protected void onEvtThink()
+ {
+ }
+
+ @Override
+ protected void onEvtAttacked(L2Character attacker)
+ {
+ L2DoorInstance me = (L2DoorInstance) _actor;
+ ThreadPoolManager.getInstance().executeTask(new onEventAttackedDoorTask(me, attacker));
+ }
+
+ @Override
+ protected void onEvtAggression(L2Character target, int aggro)
+ {
+ }
+
+ @Override
+ protected void onEvtStunned(L2Character attacker)
+ {
+ }
+
+ @Override
+ protected void onEvtSleeping(L2Character attacker)
+ {
+ }
+
+ @Override
+ protected void onEvtRooted(L2Character attacker)
+ {
+ }
+
+ @Override
+ protected void onEvtReadyToAct()
+ {
+ }
+
+ @Override
+ protected void onEvtUserCmd(Object arg0, Object arg1)
+ {
+ }
+
+ @Override
+ protected void onEvtArrived()
+ {
+ }
+
+ @Override
+ protected void onEvtArrivedRevalidate()
+ {
+ }
+
+ @Override
+ protected void onEvtArrivedBlocked(L2CharPosition blocked_at_pos)
+ {
+ }
+
+ @Override
+ protected void onEvtForgetObject(L2Object object)
+ {
+ }
+
+ @Override
+ protected void onEvtCancel()
+ {
+ }
+
+ @Override
+ protected void onEvtDead()
+ {
+ }
+
+ private class onEventAttackedDoorTask implements Runnable
+ {
+ private final L2DoorInstance _door;
+ private final L2Character _attacker;
+
+ public onEventAttackedDoorTask(L2DoorInstance door, L2Character attacker)
+ {
+ _door = door;
+ _attacker = attacker;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see java.lang.Runnable#run()
+ */
+ @Override
+ public void run()
+ {
+ for (L2DefenderInstance guard : _door.getKnownDefenders())
+ {
+ if (_actor.isInsideRadius(guard, guard.getFactionRange(), false, true) && (Math.abs(_attacker.getZ() - guard.getZ()) < 200))
+ {
+ guard.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, _attacker, 15);
+ }
+ }
+ }
+ }
+
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/ai/L2FortSiegeGuardAI.java b/L2J_Server/java/com/l2jserver/gameserver/ai/L2FortSiegeGuardAI.java
new file mode 100644
index 00000000..a0193048
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/ai/L2FortSiegeGuardAI.java
@@ -0,0 +1,980 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.ai;
+
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
+
+import java.util.concurrent.Future;
+import java.util.logging.Logger;
+
+import com.l2jserver.Config;
+import com.l2jserver.gameserver.GameTimeController;
+import com.l2jserver.gameserver.GeoData;
+import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.model.L2Effect;
+import com.l2jserver.gameserver.model.L2Object;
+import com.l2jserver.gameserver.model.L2Skill;
+import com.l2jserver.gameserver.model.actor.L2Attackable;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.actor.L2Npc;
+import com.l2jserver.gameserver.model.actor.L2Playable;
+import com.l2jserver.gameserver.model.actor.L2Summon;
+import com.l2jserver.gameserver.model.actor.instance.L2DefenderInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2FortBallistaInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2FortCommanderInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2NpcInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.templates.skills.L2SkillType;
+import com.l2jserver.gameserver.util.Util;
+import com.l2jserver.util.Rnd;
+
+/**
+ * This class manages AI of L2Attackable.
+ *
+ */
+public class L2FortSiegeGuardAI extends L2CharacterAI implements Runnable
+{
+
+ protected static final Logger _log1 = Logger.getLogger(L2FortSiegeGuardAI.class.getName());
+
+ private static final int MAX_ATTACK_TIMEOUT = 300; // int ticks, i.e. 30 seconds
+
+ /** The L2Attackable AI task executed every 1s (call onEvtThink method) */
+ private Future> _aiTask;
+
+ /** For attack AI, analysis of mob and its targets */
+ private final SelfAnalysis _selfAnalysis = new SelfAnalysis();
+
+ /** The delay after which the attacked is stopped */
+ private int _attackTimeout;
+
+ /** The L2Attackable aggro counter */
+ private int _globalAggro;
+
+ /** The flag used to indicate that a thinking action is in progress */
+ private boolean _thinking; // to prevent recursive thinking
+
+ private final int _attackRange;
+
+ /**
+ * Constructor of L2AttackableAI.
+ *
+ * @param accessor The AI accessor of the L2Character
+ */
+ public L2FortSiegeGuardAI(L2Character.AIAccessor accessor)
+ {
+ super(accessor);
+ _selfAnalysis.init();
+ _attackTimeout = Integer.MAX_VALUE;
+ _globalAggro = -10; // 10 seconds timeout of ATTACK after respawn
+ _attackRange = ((L2Attackable) _actor).getPhysicalAttackRange();
+ }
+
+ @Override
+ public void run()
+ {
+ // Launch actions corresponding to the Event Think
+ onEvtThink();
+ }
+
+ /**
+ * Return True if the target is autoattackable (depends on the actor type).
+ *
+ * Actor is a L2GuardInstance :
+ *
+ *
The target isn't a Folk or a Door
The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)
The target is in the actor Aggro range and is at the same height
The L2PcInstance target has karma (=PK)
The L2MonsterInstance
+ * target is aggressive
+ *
+ * Actor is a L2SiegeGuardInstance :
+ *
+ *
The target isn't a Folk or a Door
The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)
The target is in the actor Aggro range and is at the same height
A siege is in progress
The L2PcInstance target isn't a Defender
+ *
+ *
+ * Actor is a L2FriendlyMobInstance :
+ *
+ *
The target isn't a Folk, a Door or another L2NpcInstance
The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)
The target is in the actor Aggro range and is at the same height
The L2PcInstance target has karma (=PK)
+ *
+ * Actor is a L2MonsterInstance :
+ *
+ *
The target isn't a Folk, a Door or another L2NpcInstance
The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)
The target is in the actor Aggro range and is at the same height
The actor is Aggressive
+ *
+ * @param target The targeted L2Object
+ */
+ private boolean autoAttackCondition(L2Character target)
+ {
+ // Check if the target isn't another guard, folk or a door
+ if ((target == null) || (target instanceof L2DefenderInstance) || (target instanceof L2NpcInstance) || (target instanceof L2DoorInstance) || target.isAlikeDead() || (target instanceof L2FortBallistaInstance) || (target instanceof L2FortCommanderInstance) || (target instanceof L2Playable))
+ {
+ L2PcInstance player = null;
+ if (target instanceof L2PcInstance)
+ {
+ player = ((L2PcInstance) target);
+ }
+ else if (target instanceof L2Summon)
+ {
+ player = ((L2Summon) target).getOwner();
+ }
+ if ((player == null) || ((player.getClan() != null) && (player.getClan().getHasFort() == ((L2Npc) _actor).getFort().getFortId())))
+ {
+ return false;
+ }
+ }
+
+ // Check if the target isn't invulnerable
+ if (target.isInvul())
+ {
+ // However EffectInvincible requires to check GMs specially
+ if ((target instanceof L2PcInstance) && ((L2PcInstance) target).isGM())
+ {
+ return false;
+ }
+ if ((target instanceof L2Summon) && ((L2Summon) target).getOwner().isGM())
+ {
+ return false;
+ }
+ }
+
+ // Get the owner if the target is a summon
+ if (target instanceof L2Summon)
+ {
+ L2PcInstance owner = ((L2Summon) target).getOwner();
+ if (_actor.isInsideRadius(owner, 1000, true, false))
+ {
+ target = owner;
+ }
+ }
+
+ // Check if the target is a L2PcInstance
+ if (target instanceof L2Playable)
+ {
+ // Check if the target isn't in silent move mode AND too far (>100)
+ if (((L2Playable) target).isSilentMoving() && !_actor.isInsideRadius(target, 250, false, false))
+ {
+ return false;
+ }
+ }
+ // Los Check Here
+ return (_actor.isAutoAttackable(target) && GeoData.getInstance().canSeeTarget(_actor, target));
+
+ }
+
+ /**
+ * Set the Intention of this L2CharacterAI and create an AI Task executed every 1s (call onEvtThink method) for this L2Attackable.
+ *
+ * Caution : If actor _knowPlayer isn't EMPTY, AI_INTENTION_IDLE will be change in AI_INTENTION_ACTIVE
+ *
+ * @param intention The new Intention to set to the AI
+ * @param arg0 The first parameter of the Intention
+ * @param arg1 The second parameter of the Intention
+ */
+ @Override
+ synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
+ {
+ if (Config.DEBUG)
+ {
+ _log1.info("L2SiegeAI.changeIntention(" + intention + ", " + arg0 + ", " + arg1 + ")");
+ }
+
+ if (intention == AI_INTENTION_IDLE /* || intention == AI_INTENTION_ACTIVE */) // active becomes idle if only a summon is present
+ {
+ // Check if actor is not dead
+ if (!_actor.isAlikeDead())
+ {
+ L2Attackable npc = (L2Attackable) _actor;
+
+ // If its _knownPlayer isn't empty set the Intention to AI_INTENTION_ACTIVE
+ if (!npc.getKnownList().getKnownPlayers().isEmpty())
+ {
+ intention = AI_INTENTION_ACTIVE;
+ }
+ else
+ {
+ intention = AI_INTENTION_IDLE;
+ }
+ }
+
+ if (intention == AI_INTENTION_IDLE)
+ {
+ // Set the Intention of this L2AttackableAI to AI_INTENTION_IDLE
+ super.changeIntention(AI_INTENTION_IDLE, null, null);
+
+ // Stop AI task and detach AI from NPC
+ if (_aiTask != null)
+ {
+ _aiTask.cancel(true);
+ _aiTask = null;
+ }
+
+ // Cancel the AI
+ _accessor.detachAI();
+
+ return;
+ }
+ }
+
+ // Set the Intention of this L2AttackableAI to intention
+ super.changeIntention(intention, arg0, arg1);
+
+ // If not idle - create an AI task (schedule onEvtThink repeatedly)
+ if (_aiTask == null)
+ {
+ _aiTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(this, 1000, 1000);
+ }
+ }
+
+ /**
+ * Manage the Attack Intention : Stop current Attack (if necessary), Calculate attack timeout, Start a new Attack and Launch Think Event.
+ *
+ * @param target The L2Character to attack
+ */
+ @Override
+ protected void onIntentionAttack(L2Character target)
+ {
+ // Calculate the attack timeout
+ _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
+
+ // Manage the Attack Intention : Stop current Attack (if necessary), Start a new Attack and Launch Think Event
+ // if (_actor.getTarget() != null)
+ super.onIntentionAttack(target);
+ }
+
+ /**
+ * Manage AI standard thinks of a L2Attackable (called by onEvtThink).
+ *
+ * Actions :
+ *
+ *
Update every 1s the _globalAggro counter to come close to 0
If the actor is Aggressive and can attack, add all autoAttackable L2Character in its Aggro Range to its _aggroList, chose a target and order to attack it
If the actor can't attack, order to it to return to its
+ * home location
+ */
+ private void thinkActive()
+ {
+ L2Attackable npc = (L2Attackable) _actor;
+
+ // Update every 1s the _globalAggro counter to come close to 0
+ if (_globalAggro != 0)
+ {
+ if (_globalAggro < 0)
+ {
+ _globalAggro++;
+ }
+ else
+ {
+ _globalAggro--;
+ }
+ }
+
+ // Add all autoAttackable L2Character in L2Attackable Aggro Range to its _aggroList with 0 damage and 1 hate
+ // A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10
+ if (_globalAggro >= 0)
+ {
+ for (L2Character target : npc.getKnownList().getKnownCharactersInRadius(_attackRange))
+ {
+ if (target == null)
+ {
+ continue;
+ }
+ if (autoAttackCondition(target)) // check aggression
+ {
+ // Get the hate level of the L2Attackable against this L2Character target contained in _aggroList
+ int hating = npc.getHating(target);
+
+ // Add the attacker to the L2Attackable _aggroList with 0 damage and 1 hate
+ if (hating == 0)
+ {
+ npc.addDamageHate(target, 0, 1);
+ }
+ }
+ }
+
+ // Chose a target from its aggroList
+ L2Character hated;
+ if (_actor.isConfused())
+ {
+ hated = getAttackTarget(); // Force mobs to attack anybody if confused
+ }
+ else
+ {
+ hated = npc.getMostHated();
+ // _mostHatedAnalysis.Update(hated);
+ }
+
+ // Order to the L2Attackable to attack the target
+ if (hated != null)
+ {
+ // Get the hate level of the L2Attackable against this L2Character target contained in _aggroList
+ int aggro = npc.getHating(hated);
+
+ if ((aggro + _globalAggro) > 0)
+ {
+ // Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
+ if (!_actor.isRunning())
+ {
+ _actor.setRunning();
+ }
+
+ // Set the AI Intention to AI_INTENTION_ATTACK
+ setIntention(CtrlIntention.AI_INTENTION_ATTACK, hated, null);
+ }
+
+ return;
+ }
+
+ }
+ // Order to the L2SiegeGuardInstance to return to its home location because there's no target to attack
+ if (_actor.getWalkSpeed() >= 0)
+ {
+ if (_actor instanceof L2DefenderInstance)
+ {
+ ((L2DefenderInstance) _actor).returnHome();
+ }
+ else
+ {
+ ((L2FortCommanderInstance) _actor).returnHome();
+ }
+ }
+ }
+
+ /**
+ * Manage AI attack thinks of a L2Attackable (called by onEvtThink).
+ *
+ * Actions :
+ *
+ *
Update the attack timeout if actor is running
If target is dead or timeout is expired, stop this attack and set the Intention to AI_INTENTION_ACTIVE
Call all L2Object of its Faction inside the Faction Range
Chose a target and order to attack it with magic skill
+ * or physical attack
+ *
+ * TODO: Manage casting rules to healer mobs (like Ant Nurses)
+ */
+ private void thinkAttack()
+ {
+ if (Config.DEBUG)
+ {
+ _log1.info("L2FortSiegeGuardAI.thinkAttack(); timeout=" + (_attackTimeout - GameTimeController.getGameTicks()));
+ }
+
+ if (_attackTimeout < GameTimeController.getGameTicks())
+ {
+ // Check if the actor is running
+ if (_actor.isRunning())
+ {
+ // Set the actor movement type to walk and send Server->Client packet ChangeMoveType to all others L2PcInstance
+ _actor.setWalking();
+
+ // Calculate a new attack timeout
+ _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
+ }
+ }
+
+ L2Character attackTarget = getAttackTarget();
+ // Check if target is dead or if timeout is expired to stop this attack
+ if ((attackTarget == null) || attackTarget.isAlikeDead() || (_attackTimeout < GameTimeController.getGameTicks()))
+ {
+ // Stop hating this target after the attack timeout or if target is dead
+ if (attackTarget != null)
+ {
+ L2Attackable npc = (L2Attackable) _actor;
+ npc.stopHating(attackTarget);
+ }
+
+ // Cancel target and timeout
+ _attackTimeout = Integer.MAX_VALUE;
+ setAttackTarget(null);
+
+ // Set the AI Intention to AI_INTENTION_ACTIVE
+ setIntention(AI_INTENTION_ACTIVE, null, null);
+
+ _actor.setWalking();
+ return;
+ }
+
+ factionNotifyAndSupport();
+ attackPrepare();
+ }
+
+ private final void factionNotifyAndSupport()
+ {
+ L2Character target = getAttackTarget();
+ // Call all L2Object of its Faction inside the Faction Range
+ if ((((L2Npc) _actor).getFactionId() == null) || (target == null))
+ {
+ return;
+ }
+
+ if (target.isInvul())
+ {
+ return; // speeding it up for siege guards
+ }
+
+ String faction_id = ((L2Npc) _actor).getFactionId();
+
+ // Go through all L2Character that belong to its faction
+ // for (L2Character cha : _actor.getKnownList().getKnownCharactersInRadius(((L2NpcInstance) _actor).getFactionRange()+_actor.getTemplate().collisionRadius))
+ for (L2Character cha : _actor.getKnownList().getKnownCharactersInRadius(1000))
+ {
+ if (cha == null)
+ {
+ continue;
+ }
+
+ if (!(cha instanceof L2Npc))
+ {
+ if (_selfAnalysis.hasHealOrResurrect && (cha instanceof L2PcInstance) && ((L2Npc) _actor).getFort().getSiege().checkIsDefender(((L2PcInstance) cha).getClan()))
+ {
+ // heal friends
+ if (!_actor.isAttackingDisabled() && (cha.getCurrentHp() < (cha.getMaxHp() * 0.6)) && (_actor.getCurrentHp() > (_actor.getMaxHp() / 2)) && (_actor.getCurrentMp() > (_actor.getMaxMp() / 2)) && cha.isInCombat())
+ {
+ for (L2Skill sk : _selfAnalysis.healSkills)
+ {
+ if (_actor.getCurrentMp() < sk.getMpConsume())
+ {
+ continue;
+ }
+ if (_actor.isSkillDisabled(sk))
+ {
+ continue;
+ }
+ if (!Util.checkIfInRange(sk.getCastRange(), _actor, cha, true))
+ {
+ continue;
+ }
+
+ int chance = 5;
+ if (chance >= Rnd.get(100))
+ {
+ continue;
+ }
+ if (!GeoData.getInstance().canSeeTarget(_actor, cha))
+ {
+ break;
+ }
+
+ L2Object OldTarget = _actor.getTarget();
+ _actor.setTarget(cha);
+ clientStopMoving(null);
+ _accessor.doCast(sk);
+ _actor.setTarget(OldTarget);
+ return;
+ }
+ }
+ }
+ continue;
+ }
+
+ L2Npc npc = (L2Npc) cha;
+
+ if (!faction_id.equals(npc.getFactionId()))
+ {
+ continue;
+ }
+
+ if (npc.getAI() != null) // TODO: possibly check not needed
+ {
+ if (!npc.isDead() && (Math.abs(target.getZ() - npc.getZ()) < 600)
+ // && _actor.getAttackByList().contains(getAttackTarget())
+ && ((npc.getAI()._intention == CtrlIntention.AI_INTENTION_IDLE) || (npc.getAI()._intention == CtrlIntention.AI_INTENTION_ACTIVE))
+ // limiting aggro for siege guards
+ && target.isInsideRadius(npc, 1500, true, false) && GeoData.getInstance().canSeeTarget(npc, target))
+ {
+ // Notify the L2Object AI with EVT_AGGRESSION
+ npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, getAttackTarget(), 1);
+ return;
+ }
+ // heal friends
+ if (_selfAnalysis.hasHealOrResurrect && !_actor.isAttackingDisabled() && (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) && (_actor.getCurrentHp() > (_actor.getMaxHp() / 2)) && (_actor.getCurrentMp() > (_actor.getMaxMp() / 2)) && npc.isInCombat())
+ {
+ for (L2Skill sk : _selfAnalysis.healSkills)
+ {
+ if (_actor.getCurrentMp() < sk.getMpConsume())
+ {
+ continue;
+ }
+ if (_actor.isSkillDisabled(sk))
+ {
+ continue;
+ }
+ if (!Util.checkIfInRange(sk.getCastRange(), _actor, npc, true))
+ {
+ continue;
+ }
+
+ int chance = 4;
+ if (chance >= Rnd.get(100))
+ {
+ continue;
+ }
+ if (!GeoData.getInstance().canSeeTarget(_actor, npc))
+ {
+ break;
+ }
+
+ L2Object OldTarget = _actor.getTarget();
+ _actor.setTarget(npc);
+ clientStopMoving(null);
+ _accessor.doCast(sk);
+ _actor.setTarget(OldTarget);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ private void attackPrepare()
+ {
+ // Get all information needed to choose between physical or magical attack
+ L2Skill[] skills = null;
+ double dist_2 = 0;
+ int range = 0;
+ L2DefenderInstance sGuard;
+ if (_actor instanceof L2FortCommanderInstance)
+ {
+ sGuard = (L2FortCommanderInstance) _actor;
+ }
+ else
+ {
+ sGuard = (L2DefenderInstance) _actor;
+ }
+ L2Character attackTarget = getAttackTarget();
+
+ try
+ {
+ _actor.setTarget(attackTarget);
+ skills = _actor.getAllSkills();
+ dist_2 = _actor.getPlanDistanceSq(attackTarget.getX(), attackTarget.getY());
+ range = _actor.getPhysicalAttackRange() + _actor.getTemplate().collisionRadius + attackTarget.getTemplate().collisionRadius;
+ if (attackTarget.isMoving())
+ {
+ range += 50;
+ }
+ }
+ catch (NullPointerException e)
+ {
+ // _log.warning("AttackableAI: Attack target is NULL.");
+ _actor.setTarget(null);
+ setIntention(AI_INTENTION_IDLE, null, null);
+ return;
+ }
+
+ // never attack defenders
+ if ((attackTarget instanceof L2PcInstance) && sGuard.getFort().getSiege().checkIsDefender(((L2PcInstance) attackTarget).getClan()))
+ {
+ // Cancel the target
+ sGuard.stopHating(attackTarget);
+ _actor.setTarget(null);
+ setIntention(AI_INTENTION_IDLE, null, null);
+ return;
+ }
+
+ if (!GeoData.getInstance().canSeeTarget(_actor, attackTarget))
+ {
+ // Siege guards differ from normal mobs currently:
+ // If target cannot seen, don't attack any more
+ sGuard.stopHating(attackTarget);
+ _actor.setTarget(null);
+ setIntention(AI_INTENTION_IDLE, null, null);
+ return;
+ }
+
+ // Check if the actor isn't muted and if it is far from target
+ if (!_actor.isMuted() && (dist_2 > (range * range)))
+ {
+ // check for long ranged skills and heal/buff skills
+ for (L2Skill sk : skills)
+ {
+ int castRange = sk.getCastRange();
+
+ if ((dist_2 <= (castRange * castRange)) && (castRange > 70) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() >= _actor.getStat().getMpConsume(sk)) && !sk.isPassive())
+ {
+
+ L2Object OldTarget = _actor.getTarget();
+ if ((sk.getSkillType() == L2SkillType.BUFF) || (sk.getSkillType() == L2SkillType.HEAL))
+ {
+ boolean useSkillSelf = true;
+ if ((sk.getSkillType() == L2SkillType.HEAL) && (_actor.getCurrentHp() > (int) (_actor.getMaxHp() / 1.5)))
+ {
+ useSkillSelf = false;
+ break;
+ }
+ if (sk.getSkillType() == L2SkillType.BUFF)
+ {
+ L2Effect[] effects = _actor.getAllEffects();
+ for (int i = 0; (effects != null) && (i < effects.length); i++)
+ {
+ L2Effect effect = effects[i];
+ if (effect.getSkill() == sk)
+ {
+ useSkillSelf = false;
+ break;
+ }
+ }
+ }
+ if (useSkillSelf)
+ {
+ _actor.setTarget(_actor);
+ }
+ }
+
+ clientStopMoving(null);
+ _accessor.doCast(sk);
+ _actor.setTarget(OldTarget);
+ return;
+ }
+ }
+
+ // Check if the L2SiegeGuardInstance is attacking, knows the target and can't run
+ if (!(_actor.isAttackingNow()) && (_actor.getRunSpeed() == 0) && (_actor.getKnownList().knowsObject(attackTarget)))
+ {
+ // Cancel the target
+ _actor.getKnownList().removeKnownObject(attackTarget);
+ _actor.setTarget(null);
+ setIntention(AI_INTENTION_IDLE, null, null);
+ }
+ else
+ {
+ double dx = _actor.getX() - attackTarget.getX();
+ double dy = _actor.getY() - attackTarget.getY();
+ double dz = _actor.getZ() - attackTarget.getZ();
+ double homeX = attackTarget.getX() - sGuard.getSpawn().getLocx();
+ double homeY = attackTarget.getY() - sGuard.getSpawn().getLocy();
+
+ // Check if the L2SiegeGuardInstance isn't too far from it's home location
+ if ((((dx * dx) + (dy * dy)) > 10000) && (((homeX * homeX) + (homeY * homeY)) > 3240000) // 1800 * 1800
+ && (_actor.getKnownList().knowsObject(attackTarget)))
+ {
+ // Cancel the target
+ _actor.getKnownList().removeKnownObject(attackTarget);
+ _actor.setTarget(null);
+ setIntention(AI_INTENTION_IDLE, null, null);
+ }
+ else
+ // Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn (broadcast)
+ {
+ // Temporary hack for preventing guards jumping off towers,
+ // before replacing this with effective geodata checks and AI modification
+ if ((dz * dz) < (170 * 170)) // normally 130 if guard z coordinates correct
+ {
+ if (_selfAnalysis.isMage)
+ {
+ range = _selfAnalysis.maxCastRange - 50;
+ }
+ if (_actor.getWalkSpeed() <= 0)
+ {
+ return;
+ }
+ if (attackTarget.isMoving())
+ {
+ moveToPawn(attackTarget, range - 70);
+ }
+ else
+ {
+ moveToPawn(attackTarget, range);
+ }
+ }
+ }
+ }
+
+ return;
+
+ }
+ // Else, if the actor is muted and far from target, just "move to pawn"
+ else if (_actor.isMuted() && (dist_2 > (range * range)))
+ {
+ // Temporary hack for preventing guards jumping off towers,
+ // before replacing this with effective geodata checks and AI modification
+ double dz = _actor.getZ() - attackTarget.getZ();
+ if ((dz * dz) < (170 * 170)) // normally 130 if guard z coordinates correct
+ {
+ if (_selfAnalysis.isMage)
+ {
+ range = _selfAnalysis.maxCastRange - 50;
+ }
+ if (_actor.getWalkSpeed() <= 0)
+ {
+ return;
+ }
+ if (attackTarget.isMoving())
+ {
+ moveToPawn(attackTarget, range - 70);
+ }
+ else
+ {
+ moveToPawn(attackTarget, range);
+ }
+ }
+ return;
+ }
+ // Else, if this is close enough to attack
+ else if (dist_2 <= (range * range))
+ {
+ // Force mobs to attack anybody if confused
+ L2Character hated = null;
+ if (_actor.isConfused())
+ {
+ hated = attackTarget;
+ }
+ else
+ {
+ hated = ((L2Attackable) _actor).getMostHated();
+ }
+
+ if (hated == null)
+ {
+ setIntention(AI_INTENTION_ACTIVE, null, null);
+ return;
+ }
+ if (hated != attackTarget)
+ {
+ attackTarget = hated;
+ }
+
+ _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
+
+ // check for close combat skills && heal/buff skills
+ if (!_actor.isMuted() && (Rnd.nextInt(100) <= 5))
+ {
+ for (L2Skill sk : skills)
+ {
+ int castRange = sk.getCastRange();
+
+ if (((castRange * castRange) >= dist_2) && !sk.isPassive() && (_actor.getCurrentMp() >= _actor.getStat().getMpConsume(sk)) && !_actor.isSkillDisabled(sk))
+ {
+ L2Object OldTarget = _actor.getTarget();
+ if ((sk.getSkillType() == L2SkillType.BUFF) || (sk.getSkillType() == L2SkillType.HEAL))
+ {
+ boolean useSkillSelf = true;
+ if ((sk.getSkillType() == L2SkillType.HEAL) && (_actor.getCurrentHp() > (int) (_actor.getMaxHp() / 1.5)))
+ {
+ useSkillSelf = false;
+ break;
+ }
+ if (sk.getSkillType() == L2SkillType.BUFF)
+ {
+ L2Effect[] effects = _actor.getAllEffects();
+ for (int i = 0; (effects != null) && (i < effects.length); i++)
+ {
+ L2Effect effect = effects[i];
+ if (effect.getSkill() == sk)
+ {
+ useSkillSelf = false;
+ break;
+ }
+ }
+ }
+ if (useSkillSelf)
+ {
+ _actor.setTarget(_actor);
+ }
+ }
+
+ clientStopMoving(null);
+ _accessor.doCast(sk);
+ _actor.setTarget(OldTarget);
+ return;
+ }
+ }
+ }
+ // Finally, do the physical attack itself
+ _accessor.doAttack(attackTarget);
+ }
+ }
+
+ /**
+ * Manage AI thinking actions of a L2Attackable.
+ *
+ */
+ @Override
+ protected void onEvtThink()
+ {
+ // if(getIntention() != AI_INTENTION_IDLE && (!_actor.isVisible() || !_actor.hasAI() || !_actor.isKnownPlayers()))
+ // setIntention(AI_INTENTION_IDLE);
+
+ // Check if the actor can't use skills and if a thinking action isn't already in progress
+ if (_thinking || _actor.isCastingNow() || _actor.isAllSkillsDisabled())
+ {
+ return;
+ }
+
+ // Start thinking action
+ _thinking = true;
+
+ try
+ {
+ // Manage AI thinks of a L2Attackable
+ if (getIntention() == AI_INTENTION_ACTIVE)
+ {
+ thinkActive();
+ }
+ else if (getIntention() == AI_INTENTION_ATTACK)
+ {
+ thinkAttack();
+ }
+ }
+ finally
+ {
+ // Stop thinking action
+ _thinking = false;
+ }
+ }
+
+ /**
+ * Launch actions corresponding to the Event Attacked.
+ *
+ * Actions :
+ *
+ *
Init the attack : Calculate the attack timeout, Set the _globalAggro to 0, Add the attacker to the actor _aggroList
Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
Set the Intention to AI_INTENTION_ATTACK
+ *
+ *
+ * @param attacker The L2Character that attacks the actor
+ */
+ @Override
+ protected void onEvtAttacked(L2Character attacker)
+ {
+ // Calculate the attack timeout
+ _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
+
+ // Set the _globalAggro to 0 to permit attack even just after spawn
+ if (_globalAggro < 0)
+ {
+ _globalAggro = 0;
+ }
+
+ // Add the attacker to the _aggroList of the actor
+ ((L2Attackable) _actor).addDamageHate(attacker, 0, 1);
+
+ // Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
+ if (!_actor.isRunning())
+ {
+ _actor.setRunning();
+ }
+
+ // Set the Intention to AI_INTENTION_ATTACK
+ if (getIntention() != AI_INTENTION_ATTACK)
+ {
+ setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker, null);
+ }
+
+ super.onEvtAttacked(attacker);
+ }
+
+ /**
+ * Launch actions corresponding to the Event Aggression.
+ *
+ * Actions :
+ *
+ *
Add the target to the actor _aggroList or update hate if already present
Set the actor Intention to AI_INTENTION_ATTACK (if actor is L2GuardInstance check if it isn't too far from its home location)
+ *
+ * @param attacker The L2Character that attacks
+ * @param aggro The value of hate to add to the actor against the target
+ */
+ @Override
+ protected void onEvtAggression(L2Character target, int aggro)
+ {
+ if (_actor == null)
+ {
+ return;
+ }
+ L2Attackable me = (L2Attackable) _actor;
+
+ if (target != null)
+ {
+ // Add the target to the actor _aggroList or update hate if already present
+ me.addDamageHate(target, 0, aggro);
+
+ // Get the hate of the actor against the target
+ aggro = me.getHating(target);
+
+ if (aggro <= 0)
+ {
+ if (me.getMostHated() == null)
+ {
+ _globalAggro = -25;
+ me.clearAggroList();
+ setIntention(AI_INTENTION_IDLE, null, null);
+ }
+ return;
+ }
+
+ // Set the actor AI Intention to AI_INTENTION_ATTACK
+ if (getIntention() != CtrlIntention.AI_INTENTION_ATTACK)
+ {
+ // Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
+ if (!_actor.isRunning())
+ {
+ _actor.setRunning();
+ }
+
+ L2DefenderInstance sGuard;
+ if (_actor instanceof L2FortCommanderInstance)
+ {
+ sGuard = (L2FortCommanderInstance) _actor;
+ }
+ else
+ {
+ sGuard = (L2DefenderInstance) _actor;
+ }
+ double homeX = target.getX() - sGuard.getSpawn().getLocx();
+ double homeY = target.getY() - sGuard.getSpawn().getLocy();
+
+ // Check if the L2SiegeGuardInstance is not too far from its home location
+ if (((homeX * homeX) + (homeY * homeY)) < 3240000)
+ {
+ setIntention(CtrlIntention.AI_INTENTION_ATTACK, target, null);
+ }
+ }
+ }
+ else
+ {
+ // currently only for setting lower general aggro
+ if (aggro >= 0)
+ {
+ return;
+ }
+
+ L2Character mostHated = me.getMostHated();
+ if (mostHated == null)
+ {
+ _globalAggro = -25;
+ return;
+ }
+ for (L2Character aggroed : me.getAggroList().keySet())
+ {
+ me.addDamageHate(aggroed, 0, aggro);
+ }
+
+ aggro = me.getHating(mostHated);
+ if (aggro <= 0)
+ {
+ _globalAggro = -25;
+ me.clearAggroList();
+ setIntention(AI_INTENTION_IDLE, null, null);
+ }
+ }
+ }
+
+ @Override
+ public void stopAITask()
+ {
+ if (_aiTask != null)
+ {
+ _aiTask.cancel(false);
+ _aiTask = null;
+ }
+ _accessor.detachAI();
+ super.stopAITask();
+ }
+
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/ai/L2NpcWalkerAI.java b/L2J_Server/java/com/l2jserver/gameserver/ai/L2NpcWalkerAI.java
new file mode 100644
index 00000000..a1a9a319
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/ai/L2NpcWalkerAI.java
@@ -0,0 +1,240 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.ai;
+
+import java.util.List;
+
+import com.l2jserver.Config;
+import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.datatables.NpcWalkerRoutesTable;
+import com.l2jserver.gameserver.model.L2CharPosition;
+import com.l2jserver.gameserver.model.L2NpcWalkerNode;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.actor.instance.L2NpcWalkerInstance;
+
+public class L2NpcWalkerAI extends L2CharacterAI implements Runnable
+{
+ private static final int DEFAULT_MOVE_DELAY = 0;
+
+ private long _nextMoveTime;
+
+ private boolean _walkingToNextPoint = false;
+
+ /**
+ * home points for xyz
+ */
+ int _homeX, _homeY, _homeZ;
+
+ /**
+ * route of the current npc
+ */
+ private List _route;
+
+ /**
+ * current node
+ */
+ private int _currentPos;
+
+ /**
+ * Constructor of L2CharacterAI.
+ *
+ * @param accessor The AI accessor of the L2Character
+ */
+ public L2NpcWalkerAI(L2Character.AIAccessor accessor)
+ {
+ super(accessor);
+
+ if (!Config.ALLOW_NPC_WALKERS)
+ {
+ return;
+ }
+
+ _route = NpcWalkerRoutesTable.getInstance().getRouteForNpc(getActor().getNpcId());
+
+ // Here we need 1 second initial delay cause getActor().hasAI() will return null...
+ // Constructor of L2NpcWalkerAI is called faster then ai object is attached in L2NpcWalkerInstance
+ if (_route != null)
+ {
+ ThreadPoolManager.getInstance().scheduleAiAtFixedRate(this, 1000, 1000);
+ }
+ else
+ {
+ _log.warning(getClass().getSimpleName() + ": Missing route data! Npc: " + _actor);
+ }
+ }
+
+ @Override
+ public void run()
+ {
+ onEvtThink();
+ }
+
+ @Override
+ protected void onEvtThink()
+ {
+ if (!Config.ALLOW_NPC_WALKERS)
+ {
+ return;
+ }
+
+ if (isWalkingToNextPoint())
+ {
+ checkArrived();
+ return;
+ }
+
+ if (_nextMoveTime < System.currentTimeMillis())
+ {
+ walkToLocation();
+ }
+ }
+
+ /**
+ * If npc can't walk to it's target then just teleport to next point
+ * @param blocked_at_pos ignoring it
+ */
+ @Override
+ protected void onEvtArrivedBlocked(L2CharPosition blocked_at_pos)
+ {
+ _log.warning("NpcWalker ID: " + getActor().getNpcId() + ": Blocked at rote position [" + _currentPos + "], coords: " + blocked_at_pos.x + ", " + blocked_at_pos.y + ", " + blocked_at_pos.z + ". Teleporting to next point");
+
+ int destinationX = _route.get(_currentPos).getMoveX();
+ int destinationY = _route.get(_currentPos).getMoveY();
+ int destinationZ = _route.get(_currentPos).getMoveZ();
+
+ getActor().teleToLocation(destinationX, destinationY, destinationZ, false);
+ super.onEvtArrivedBlocked(blocked_at_pos);
+ }
+
+ private void checkArrived()
+ {
+ int destinationX = _route.get(_currentPos).getMoveX();
+ int destinationY = _route.get(_currentPos).getMoveY();
+ int destinationZ = _route.get(_currentPos).getMoveZ();
+
+ if (getActor().isInsideRadius(destinationX, destinationY, destinationZ, 5, false, false))
+ {
+ int id = _route.get(_currentPos).getChatId();
+ String chat = null;
+ if (id == 0)
+ {
+ chat = _route.get(_currentPos).getChatText();
+ }
+
+ if ((id > 0) || ((chat != null) && !chat.isEmpty()))
+ {
+ getActor().broadcastChat(chat, id);
+ }
+
+ // time in millis
+ long delay = _route.get(_currentPos).getDelay() * 1000;
+
+ // sleeps between each move
+ if (delay <= 0)
+ {
+ delay = DEFAULT_MOVE_DELAY;
+ if (Config.DEVELOPER)
+ {
+ _log.warning("Wrong Delay Set in Npc Walker Functions = " + delay + " secs, using default delay: " + DEFAULT_MOVE_DELAY + " secs instead.");
+ }
+ }
+
+ _nextMoveTime = System.currentTimeMillis() + delay;
+ setWalkingToNextPoint(false);
+ }
+ }
+
+ private void walkToLocation()
+ {
+ if (_currentPos < (_route.size() - 1))
+ {
+ _currentPos++;
+ }
+ else
+ {
+ _currentPos = 0;
+ }
+
+ boolean moveType = _route.get(_currentPos).getRunning();
+
+ /**
+ * false - walking true - Running
+ */
+ if (moveType)
+ {
+ getActor().setRunning();
+ }
+ else
+ {
+ getActor().setWalking();
+ }
+
+ // now we define destination
+ int destinationX = _route.get(_currentPos).getMoveX();
+ int destinationY = _route.get(_currentPos).getMoveY();
+ int destinationZ = _route.get(_currentPos).getMoveZ();
+
+ // notify AI of MOVE_TO
+ setWalkingToNextPoint(true);
+
+ setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(destinationX, destinationY, destinationZ, 0));
+ }
+
+ @Override
+ public L2NpcWalkerInstance getActor()
+ {
+ return (L2NpcWalkerInstance) super.getActor();
+ }
+
+ public int getHomeX()
+ {
+ return _homeX;
+ }
+
+ public int getHomeY()
+ {
+ return _homeY;
+ }
+
+ public int getHomeZ()
+ {
+ return _homeZ;
+ }
+
+ public void setHomeX(int homeX)
+ {
+ _homeX = homeX;
+ }
+
+ public void setHomeY(int homeY)
+ {
+ _homeY = homeY;
+ }
+
+ public void setHomeZ(int homeZ)
+ {
+ _homeZ = homeZ;
+ }
+
+ public boolean isWalkingToNextPoint()
+ {
+ return _walkingToNextPoint;
+ }
+
+ public void setWalkingToNextPoint(boolean value)
+ {
+ _walkingToNextPoint = value;
+ }
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/ai/L2PlayableAI.java b/L2J_Server/java/com/l2jserver/gameserver/ai/L2PlayableAI.java
new file mode 100644
index 00000000..7e78ebf0
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/ai/L2PlayableAI.java
@@ -0,0 +1,136 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.ai;
+
+import com.l2jserver.gameserver.model.L2Object;
+import com.l2jserver.gameserver.model.L2Skill;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.actor.L2Character.AIAccessor;
+import com.l2jserver.gameserver.model.actor.L2Playable;
+import com.l2jserver.gameserver.network.SystemMessageId;
+
+/**
+ * This class manages AI of L2Playable.
+ *
+ * L2PlayableAI :
+ *
+ *
L2SummonAI
L2PlayerAI
+ *
+ * @author JIV
+ */
+public abstract class L2PlayableAI extends L2CharacterAI
+{
+
+ /**
+ * @param accessor
+ */
+ public L2PlayableAI(AIAccessor accessor)
+ {
+ super(accessor);
+ }
+
+ /**
+ * @see com.l2jserver.gameserver.ai.L2CharacterAI#onIntentionAttack(com.l2jserver.gameserver.model.actor.L2Character)
+ */
+ @Override
+ protected void onIntentionAttack(L2Character target)
+ {
+ if (target instanceof L2Playable)
+ {
+ if (target.getActingPlayer().getProtectionBlessing() && ((_actor.getActingPlayer().getLevel() - target.getActingPlayer().getLevel()) >= 10) && (_actor.getActingPlayer().getKarma() > 0) && !(target.isInsideZone(L2Character.ZONE_PVP)))
+ {
+ // If attacker have karma and have level >= 10 than his target and target have
+ // Newbie Protection Buff,
+ _actor.getActingPlayer().sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
+ clientActionFailed();
+ return;
+ }
+
+ if (_actor.getActingPlayer().getProtectionBlessing() && ((target.getActingPlayer().getLevel() - _actor.getActingPlayer().getLevel()) >= 10) && (target.getActingPlayer().getKarma() > 0) && !(target.isInsideZone(L2Character.ZONE_PVP)))
+ {
+ // If target have karma and have level >= 10 than his target and actor have
+ // Newbie Protection Buff,
+ _actor.getActingPlayer().sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
+ clientActionFailed();
+ return;
+ }
+
+ if (target.getActingPlayer().isCursedWeaponEquipped() && (_actor.getActingPlayer().getLevel() <= 20))
+ {
+ _actor.getActingPlayer().sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
+ clientActionFailed();
+ return;
+ }
+
+ if (_actor.getActingPlayer().isCursedWeaponEquipped() && (target.getActingPlayer().getLevel() <= 20))
+ {
+ _actor.getActingPlayer().sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
+ clientActionFailed();
+ return;
+ }
+ }
+
+ super.onIntentionAttack(target);
+ }
+
+ /**
+ * @see com.l2jserver.gameserver.ai.L2CharacterAI#onIntentionCast(com.l2jserver.gameserver.model.L2Skill, com.l2jserver.gameserver.model.L2Object)
+ */
+ @Override
+ protected void onIntentionCast(L2Skill skill, L2Object target)
+ {
+ if ((target instanceof L2Playable) && skill.isOffensive())
+ {
+ if (target.getActingPlayer().getProtectionBlessing() && ((_actor.getActingPlayer().getLevel() - target.getActingPlayer().getLevel()) >= 10) && (_actor.getActingPlayer().getKarma() > 0) && !(((L2Playable) target).isInsideZone(L2Character.ZONE_PVP)))
+ {
+ // If attacker have karma and have level >= 10 than his target and target have
+ // Newbie Protection Buff,
+ _actor.getActingPlayer().sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
+ clientActionFailed();
+ _actor.setIsCastingNow(false);
+ return;
+ }
+
+ if (_actor.getActingPlayer().getProtectionBlessing() && ((target.getActingPlayer().getLevel() - _actor.getActingPlayer().getLevel()) >= 10) && (target.getActingPlayer().getKarma() > 0) && !(((L2Playable) target).isInsideZone(L2Character.ZONE_PVP)))
+ {
+ // If target have karma and have level >= 10 than his target and actor have
+ // Newbie Protection Buff,
+ _actor.getActingPlayer().sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
+ clientActionFailed();
+ _actor.setIsCastingNow(false);
+ return;
+ }
+
+ if (target.getActingPlayer().isCursedWeaponEquipped() && (_actor.getActingPlayer().getLevel() <= 20))
+ {
+ _actor.getActingPlayer().sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
+ clientActionFailed();
+ _actor.setIsCastingNow(false);
+ return;
+ }
+
+ if (_actor.getActingPlayer().isCursedWeaponEquipped() && (target.getActingPlayer().getLevel() <= 20))
+ {
+ _actor.getActingPlayer().sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
+ clientActionFailed();
+ _actor.setIsCastingNow(false);
+ return;
+ }
+ }
+
+ super.onIntentionCast(skill, target);
+ }
+
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/ai/L2PlayerAI.java b/L2J_Server/java/com/l2jserver/gameserver/ai/L2PlayerAI.java
new file mode 100644
index 00000000..2e31a6dd
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/ai/L2PlayerAI.java
@@ -0,0 +1,387 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.ai;
+
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_CAST;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_INTERACT;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_MOVE_TO;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_PICK_UP;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_REST;
+
+import com.l2jserver.Config;
+import com.l2jserver.gameserver.model.L2CharPosition;
+import com.l2jserver.gameserver.model.L2Object;
+import com.l2jserver.gameserver.model.L2Skill;
+import com.l2jserver.gameserver.model.L2Skill.SkillTargetType;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.actor.L2Character.AIAccessor;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2StaticObjectInstance;
+
+public class L2PlayerAI extends L2PlayableAI
+{
+
+ private boolean _thinking; // to prevent recursive thinking
+
+ IntentionCommand _nextIntention = null;
+
+ public L2PlayerAI(AIAccessor accessor)
+ {
+ super(accessor);
+ }
+
+ void saveNextIntention(CtrlIntention intention, Object arg0, Object arg1)
+ {
+ _nextIntention = new IntentionCommand(intention, arg0, arg1);
+ }
+
+ @Override
+ public IntentionCommand getNextIntention()
+ {
+ return _nextIntention;
+ }
+
+ /**
+ * Saves the current Intention for this L2PlayerAI if necessary and calls changeIntention in AbstractAI.
+ *
+ * @param intention The new Intention to set to the AI
+ * @param arg0 The first parameter of the Intention
+ * @param arg1 The second parameter of the Intention
+ */
+ @Override
+ synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
+ {
+ /*
+ * if (Config.DEBUG) _log.warning("L2PlayerAI: changeIntention -> " + intention + " " + arg0 + " " + arg1);
+ */
+
+ // do nothing unless CAST intention
+ // however, forget interrupted actions when starting to use an offensive skill
+ if ((intention != AI_INTENTION_CAST) || ((arg0 != null) && ((L2Skill) arg0).isOffensive()))
+ {
+ _nextIntention = null;
+ super.changeIntention(intention, arg0, arg1);
+ return;
+ }
+
+ // do nothing if next intention is same as current one.
+ if ((intention == _intention) && (arg0 == _intentionArg0) && (arg1 == _intentionArg1))
+ {
+ super.changeIntention(intention, arg0, arg1);
+ return;
+ }
+
+ // save current intention so it can be used after cast
+ saveNextIntention(_intention, _intentionArg0, _intentionArg1);
+ super.changeIntention(intention, arg0, arg1);
+ }
+
+ /**
+ * Launch actions corresponding to the Event ReadyToAct.
+ *
+ * Actions :
+ *
+ *
+ *
+ */
+ @Override
+ protected void onEvtCancel()
+ {
+ _nextIntention = null;
+ super.onEvtCancel();
+ }
+
+ /**
+ * Finalize the casting of a skill. This method overrides L2CharacterAI method.
+ *
+ * What it does: Check if actual intention is set to CAST and, if so, retrieves latest intention before the actual CAST and set it as the current intention for the player
+ */
+ @Override
+ protected void onEvtFinishCasting()
+ {
+ if (getIntention() == AI_INTENTION_CAST)
+ {
+ // run interrupted or next intention
+
+ IntentionCommand nextIntention = _nextIntention;
+ if (nextIntention != null)
+ {
+ if (nextIntention._crtlIntention != AI_INTENTION_CAST) // previous state shouldn't be casting
+ {
+ setIntention(nextIntention._crtlIntention, nextIntention._arg0, nextIntention._arg1);
+ }
+ else
+ {
+ setIntention(AI_INTENTION_IDLE);
+ }
+ }
+ else
+ {
+ /*
+ * if (Config.DEBUG) _log.warning("L2PlayerAI: no previous intention set... Setting it to IDLE");
+ */
+ // set intention to idle if skill doesn't change intention.
+ setIntention(AI_INTENTION_IDLE);
+ }
+ }
+ }
+
+ @Override
+ protected void onIntentionRest()
+ {
+ if (getIntention() != AI_INTENTION_REST)
+ {
+ changeIntention(AI_INTENTION_REST, null, null);
+ setTarget(null);
+ if (getAttackTarget() != null)
+ {
+ setAttackTarget(null);
+ }
+ clientStopMoving(null);
+ }
+ }
+
+ @Override
+ protected void onIntentionActive()
+ {
+ setIntention(AI_INTENTION_IDLE);
+ }
+
+ /**
+ * Manage the Move To Intention : Stop current Attack and Launch a Move to Location Task.
+ *
+ * Actions :
+ *
+ *
Stop the actor auto-attack server side AND client side by sending Server->Client packet AutoAttackStop (broadcast)
Set the Intention of this AI to AI_INTENTION_MOVE_TO
Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet
+ * CharMoveToLocation (broadcast)
+ *
+ */
+ @Override
+ protected void onIntentionMoveTo(L2CharPosition pos)
+ {
+ if (getIntention() == AI_INTENTION_REST)
+ {
+ // Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
+ clientActionFailed();
+ return;
+ }
+
+ if (_actor.isAllSkillsDisabled() || _actor.isCastingNow() || _actor.isAttackingNow())
+ {
+ clientActionFailed();
+ saveNextIntention(AI_INTENTION_MOVE_TO, pos, null);
+ return;
+ }
+
+ // Set the Intention of this AbstractAI to AI_INTENTION_MOVE_TO
+ changeIntention(AI_INTENTION_MOVE_TO, pos, null);
+
+ // Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
+ clientStopAutoAttack();
+
+ // Abort the attack of the L2Character and send Server->Client ActionFailed packet
+ _actor.abortAttack();
+
+ // Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast)
+ moveTo(pos.x, pos.y, pos.z);
+ }
+
+ @Override
+ protected void clientNotifyDead()
+ {
+ _clientMovingToPawnOffset = 0;
+ _clientMoving = false;
+
+ super.clientNotifyDead();
+ }
+
+ private void thinkAttack()
+ {
+ L2Character target = getAttackTarget();
+ if (target == null)
+ {
+ return;
+ }
+ if (checkTargetLostOrDead(target))
+ {
+ // Notify the target
+ setAttackTarget(null);
+ return;
+ }
+ if (maybeMoveToPawn(target, _actor.getPhysicalAttackRange()))
+ {
+ return;
+ }
+
+ _accessor.doAttack(target);
+ }
+
+ private void thinkCast()
+ {
+ L2Character target = getCastTarget();
+ if (Config.DEBUG)
+ {
+ _log.warning("L2PlayerAI: thinkCast -> Start");
+ }
+
+ if ((_skill.getTargetType() == SkillTargetType.TARGET_GROUND) && (_actor instanceof L2PcInstance))
+ {
+ if (maybeMoveToPosition(((L2PcInstance) _actor).getCurrentSkillWorldPosition(), _actor.getMagicalAttackRange(_skill)))
+ {
+ _actor.setIsCastingNow(false);
+ return;
+ }
+ }
+ else
+ {
+ if (checkTargetLost(target))
+ {
+ if (_skill.isOffensive() && (getAttackTarget() != null))
+ {
+ // Notify the target
+ setCastTarget(null);
+ }
+ _actor.setIsCastingNow(false);
+ return;
+ }
+ if ((target != null) && maybeMoveToPawn(target, _actor.getMagicalAttackRange(_skill)))
+ {
+ _actor.setIsCastingNow(false);
+ return;
+ }
+ }
+
+ if ((_skill.getHitTime() > 50) && !_skill.isSimultaneousCast())
+ {
+ clientStopMoving(null);
+ }
+
+ L2Object oldTarget = _actor.getTarget();
+ if ((oldTarget != null) && (target != null) && (oldTarget != target))
+ {
+ // Replace the current target by the cast target
+ _actor.setTarget(getCastTarget());
+ // Launch the Cast of the skill
+ _accessor.doCast(_skill);
+ // Restore the initial target
+ _actor.setTarget(oldTarget);
+ }
+ else
+ {
+ _accessor.doCast(_skill);
+ }
+ }
+
+ private void thinkPickUp()
+ {
+ if (_actor.isAllSkillsDisabled() || _actor.isCastingNow())
+ {
+ return;
+ }
+ L2Object target = getTarget();
+ if (checkTargetLost(target))
+ {
+ return;
+ }
+ if (maybeMoveToPawn(target, 36))
+ {
+ return;
+ }
+ setIntention(AI_INTENTION_IDLE);
+ ((L2PcInstance.AIAccessor) _accessor).doPickupItem(target);
+ }
+
+ private void thinkInteract()
+ {
+ if (_actor.isAllSkillsDisabled() || _actor.isCastingNow())
+ {
+ return;
+ }
+ L2Object target = getTarget();
+ if (checkTargetLost(target))
+ {
+ return;
+ }
+ if (maybeMoveToPawn(target, 36))
+ {
+ return;
+ }
+ if (!(target instanceof L2StaticObjectInstance))
+ {
+ ((L2PcInstance.AIAccessor) _accessor).doInteract((L2Character) target);
+ }
+ setIntention(AI_INTENTION_IDLE);
+ }
+
+ @Override
+ protected void onEvtThink()
+ {
+ if (_thinking && (getIntention() != AI_INTENTION_CAST))
+ {
+ return;
+ }
+
+ /*
+ * if (Config.DEBUG) _log.warning("L2PlayerAI: onEvtThink -> Check intention");
+ */
+
+ _thinking = true;
+ try
+ {
+ if (getIntention() == AI_INTENTION_ATTACK)
+ {
+ thinkAttack();
+ }
+ else if (getIntention() == AI_INTENTION_CAST)
+ {
+ thinkCast();
+ }
+ else if (getIntention() == AI_INTENTION_PICK_UP)
+ {
+ thinkPickUp();
+ }
+ else if (getIntention() == AI_INTENTION_INTERACT)
+ {
+ thinkInteract();
+ }
+ }
+ finally
+ {
+ _thinking = false;
+ }
+ }
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/ai/L2SiegeGuardAI.java b/L2J_Server/java/com/l2jserver/gameserver/ai/L2SiegeGuardAI.java
new file mode 100644
index 00000000..35bd72bd
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/ai/L2SiegeGuardAI.java
@@ -0,0 +1,940 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.ai;
+
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
+
+import java.util.concurrent.Future;
+
+import com.l2jserver.Config;
+import com.l2jserver.gameserver.GameTimeController;
+import com.l2jserver.gameserver.GeoData;
+import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.model.L2Effect;
+import com.l2jserver.gameserver.model.L2Object;
+import com.l2jserver.gameserver.model.L2Skill;
+import com.l2jserver.gameserver.model.actor.L2Attackable;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.actor.L2Npc;
+import com.l2jserver.gameserver.model.actor.L2Playable;
+import com.l2jserver.gameserver.model.actor.L2Summon;
+import com.l2jserver.gameserver.model.actor.instance.L2DefenderInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2NpcInstance;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.templates.skills.L2SkillType;
+import com.l2jserver.gameserver.util.Util;
+import com.l2jserver.util.Rnd;
+
+/**
+ * This class manages AI of L2Attackable.
+ *
+ */
+public class L2SiegeGuardAI extends L2CharacterAI implements Runnable
+{
+
+ // protected static final Logger _log = Logger.getLogger(L2SiegeGuardAI.class.getName());
+
+ private static final int MAX_ATTACK_TIMEOUT = 300; // int ticks, i.e. 30 seconds
+
+ /** The L2Attackable AI task executed every 1s (call onEvtThink method) */
+ private Future> _aiTask;
+
+ /** For attack AI, analysis of mob and its targets */
+ private final SelfAnalysis _selfAnalysis = new SelfAnalysis();
+ // private TargetAnalysis _mostHatedAnalysis = new TargetAnalysis();
+
+ /** The delay after which the attacked is stopped */
+ private int _attackTimeout;
+
+ /** The L2Attackable aggro counter */
+ private int _globalAggro;
+
+ /** The flag used to indicate that a thinking action is in progress */
+ private boolean _thinking; // to prevent recursive thinking
+
+ private final int _attackRange;
+
+ /**
+ * Constructor of L2AttackableAI.
+ *
+ * @param accessor The AI accessor of the L2Character
+ */
+ public L2SiegeGuardAI(L2Character.AIAccessor accessor)
+ {
+ super(accessor);
+ _selfAnalysis.init();
+ _attackTimeout = Integer.MAX_VALUE;
+ _globalAggro = -10; // 10 seconds timeout of ATTACK after respawn
+ _attackRange = ((L2Attackable) _actor).getPhysicalAttackRange();
+ }
+
+ @Override
+ public void run()
+ {
+ // Launch actions corresponding to the Event Think
+ onEvtThink();
+
+ }
+
+ /**
+ * Return True if the target is autoattackable (depends on the actor type).
+ *
+ * Actor is a L2GuardInstance :
+ *
+ *
The target isn't a Folk or a Door
The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)
The target is in the actor Aggro range and is at the same height
The L2PcInstance target has karma (=PK)
The L2MonsterInstance
+ * target is aggressive
+ *
+ * Actor is a L2SiegeGuardInstance :
+ *
+ *
The target isn't a Folk or a Door
The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)
The target is in the actor Aggro range and is at the same height
A siege is in progress
The L2PcInstance target isn't a Defender
+ *
+ *
+ * Actor is a L2FriendlyMobInstance :
+ *
+ *
The target isn't a Folk, a Door or another L2NpcInstance
The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)
The target is in the actor Aggro range and is at the same height
The L2PcInstance target has karma (=PK)
+ *
+ * Actor is a L2MonsterInstance :
+ *
+ *
The target isn't a Folk, a Door or another L2NpcInstance
The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)
The target is in the actor Aggro range and is at the same height
The actor is Aggressive
+ *
+ * @param target The targeted L2Object
+ */
+ private boolean autoAttackCondition(L2Character target)
+ {
+ // Check if the target isn't another guard, folk or a door
+ if ((target == null) || (target instanceof L2DefenderInstance) || (target instanceof L2NpcInstance) || (target instanceof L2DoorInstance) || target.isAlikeDead())
+ {
+ return false;
+ }
+
+ // Check if the target isn't invulnerable
+ if (target.isInvul())
+ {
+ // However EffectInvincible requires to check GMs specially
+ if ((target instanceof L2PcInstance) && ((L2PcInstance) target).isGM())
+ {
+ return false;
+ }
+ if ((target instanceof L2Summon) && ((L2Summon) target).getOwner().isGM())
+ {
+ return false;
+ }
+ }
+
+ // Get the owner if the target is a summon
+ if (target instanceof L2Summon)
+ {
+ L2PcInstance owner = ((L2Summon) target).getOwner();
+ if (_actor.isInsideRadius(owner, 1000, true, false))
+ {
+ target = owner;
+ }
+ }
+
+ // Check if the target is a L2PcInstance
+ if (target instanceof L2Playable)
+ {
+ // Check if the target isn't in silent move mode AND too far (>100)
+ if (((L2Playable) target).isSilentMoving() && !_actor.isInsideRadius(target, 250, false, false))
+ {
+ return false;
+ }
+ }
+ // Los Check Here
+ return (_actor.isAutoAttackable(target) && GeoData.getInstance().canSeeTarget(_actor, target));
+
+ }
+
+ /**
+ * Set the Intention of this L2CharacterAI and create an AI Task executed every 1s (call onEvtThink method) for this L2Attackable.
+ *
+ * Caution : If actor _knowPlayer isn't EMPTY, AI_INTENTION_IDLE will be change in AI_INTENTION_ACTIVE
+ *
+ * @param intention The new Intention to set to the AI
+ * @param arg0 The first parameter of the Intention
+ * @param arg1 The second parameter of the Intention
+ */
+ @Override
+ synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
+ {
+ if (Config.DEBUG)
+ {
+ _log.info("L2SiegeAI.changeIntention(" + intention + ", " + arg0 + ", " + arg1 + ")");
+ }
+
+ if (intention == AI_INTENTION_IDLE /* || intention == AI_INTENTION_ACTIVE */) // active becomes idle if only a summon is present
+ {
+ // Check if actor is not dead
+ if (!_actor.isAlikeDead())
+ {
+ L2Attackable npc = (L2Attackable) _actor;
+
+ // If its _knownPlayer isn't empty set the Intention to AI_INTENTION_ACTIVE
+ if (!npc.getKnownList().getKnownPlayers().isEmpty())
+ {
+ intention = AI_INTENTION_ACTIVE;
+ }
+ else
+ {
+ intention = AI_INTENTION_IDLE;
+ }
+ }
+
+ if (intention == AI_INTENTION_IDLE)
+ {
+ // Set the Intention of this L2AttackableAI to AI_INTENTION_IDLE
+ super.changeIntention(AI_INTENTION_IDLE, null, null);
+
+ // Stop AI task and detach AI from NPC
+ if (_aiTask != null)
+ {
+ _aiTask.cancel(true);
+ _aiTask = null;
+ }
+
+ // Cancel the AI
+ _accessor.detachAI();
+
+ return;
+ }
+ }
+
+ // Set the Intention of this L2AttackableAI to intention
+ super.changeIntention(intention, arg0, arg1);
+
+ // If not idle - create an AI task (schedule onEvtThink repeatedly)
+ if (_aiTask == null)
+ {
+ _aiTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(this, 1000, 1000);
+ }
+ }
+
+ /**
+ * Manage the Attack Intention : Stop current Attack (if necessary), Calculate attack timeout, Start a new Attack and Launch Think Event.
+ *
+ * @param target The L2Character to attack
+ */
+ @Override
+ protected void onIntentionAttack(L2Character target)
+ {
+ // Calculate the attack timeout
+ _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
+
+ // Manage the Attack Intention : Stop current Attack (if necessary), Start a new Attack and Launch Think Event
+ // if (_actor.getTarget() != null)
+ super.onIntentionAttack(target);
+ }
+
+ /**
+ * Manage AI standard thinks of a L2Attackable (called by onEvtThink).
+ *
+ * Actions :
+ *
+ *
Update every 1s the _globalAggro counter to come close to 0
If the actor is Aggressive and can attack, add all autoAttackable L2Character in its Aggro Range to its _aggroList, chose a target and order to attack it
If the actor can't attack, order to it to return to its
+ * home location
+ */
+ private void thinkActive()
+ {
+ L2Attackable npc = (L2Attackable) _actor;
+
+ // Update every 1s the _globalAggro counter to come close to 0
+ if (_globalAggro != 0)
+ {
+ if (_globalAggro < 0)
+ {
+ _globalAggro++;
+ }
+ else
+ {
+ _globalAggro--;
+ }
+ }
+
+ // Add all autoAttackable L2Character in L2Attackable Aggro Range to its _aggroList with 0 damage and 1 hate
+ // A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10
+ if (_globalAggro >= 0)
+ {
+ for (L2Character target : npc.getKnownList().getKnownCharactersInRadius(_attackRange))
+ {
+ if (target == null)
+ {
+ continue;
+ }
+ if (autoAttackCondition(target)) // check aggression
+ {
+ // Get the hate level of the L2Attackable against this L2Character target contained in _aggroList
+ int hating = npc.getHating(target);
+
+ // Add the attacker to the L2Attackable _aggroList with 0 damage and 1 hate
+ if (hating == 0)
+ {
+ npc.addDamageHate(target, 0, 1);
+ }
+ }
+ }
+
+ // Chose a target from its aggroList
+ L2Character hated;
+ if (_actor.isConfused())
+ {
+ hated = getAttackTarget(); // Force mobs to attack anybody if confused
+ }
+ else
+ {
+ hated = npc.getMostHated();
+ // _mostHatedAnalysis.Update(hated);
+ }
+
+ // Order to the L2Attackable to attack the target
+ if (hated != null)
+ {
+ // Get the hate level of the L2Attackable against this L2Character target contained in _aggroList
+ int aggro = npc.getHating(hated);
+
+ if ((aggro + _globalAggro) > 0)
+ {
+ // Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
+ if (!_actor.isRunning())
+ {
+ _actor.setRunning();
+ }
+
+ // Set the AI Intention to AI_INTENTION_ATTACK
+ setIntention(CtrlIntention.AI_INTENTION_ATTACK, hated, null);
+ }
+
+ return;
+ }
+
+ }
+ // Order to the L2DefenderInstance to return to its home location because there's no target to attack
+ ((L2DefenderInstance) _actor).returnHome();
+ }
+
+ /**
+ * Manage AI attack thinks of a L2Attackable (called by onEvtThink).
+ *
+ * Actions :
+ *
+ *
Update the attack timeout if actor is running
If target is dead or timeout is expired, stop this attack and set the Intention to AI_INTENTION_ACTIVE
Call all L2Object of its Faction inside the Faction Range
Chose a target and order to attack it with magic skill
+ * or physical attack
+ *
+ * TODO: Manage casting rules to healer mobs (like Ant Nurses)
+ */
+ private void thinkAttack()
+ {
+ if (Config.DEBUG)
+ {
+ _log.info("L2SiegeGuardAI.thinkAttack(); timeout=" + (_attackTimeout - GameTimeController.getGameTicks()));
+ }
+
+ if (_attackTimeout < GameTimeController.getGameTicks())
+ {
+ // Check if the actor is running
+ if (_actor.isRunning())
+ {
+ // Set the actor movement type to walk and send Server->Client packet ChangeMoveType to all others L2PcInstance
+ _actor.setWalking();
+
+ // Calculate a new attack timeout
+ _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
+ }
+ }
+
+ L2Character attackTarget = getAttackTarget();
+ // Check if target is dead or if timeout is expired to stop this attack
+ if ((attackTarget == null) || attackTarget.isAlikeDead() || (_attackTimeout < GameTimeController.getGameTicks()))
+ {
+ // Stop hating this target after the attack timeout or if target is dead
+ if (attackTarget != null)
+ {
+ L2Attackable npc = (L2Attackable) _actor;
+ npc.stopHating(attackTarget);
+ }
+
+ // Cancel target and timeout
+ _attackTimeout = Integer.MAX_VALUE;
+ setAttackTarget(null);
+
+ // Set the AI Intention to AI_INTENTION_ACTIVE
+ setIntention(AI_INTENTION_ACTIVE, null, null);
+
+ _actor.setWalking();
+ return;
+ }
+
+ factionNotifyAndSupport();
+ attackPrepare();
+ }
+
+ private final void factionNotifyAndSupport()
+ {
+ L2Character target = getAttackTarget();
+ // Call all L2Object of its Faction inside the Faction Range
+ if ((((L2Npc) _actor).getFactionId() == null) || (target == null))
+ {
+ return;
+ }
+
+ if (target.isInvul())
+ {
+ return; // speeding it up for siege guards
+ }
+
+ String faction_id = ((L2Npc) _actor).getFactionId();
+
+ // Go through all L2Character that belong to its faction
+ // for (L2Character cha : _actor.getKnownList().getKnownCharactersInRadius(((L2NpcInstance) _actor).getFactionRange()+_actor.getTemplate().collisionRadius))
+ for (L2Character cha : _actor.getKnownList().getKnownCharactersInRadius(1000))
+ {
+ if (cha == null)
+ {
+ continue;
+ }
+
+ if (!(cha instanceof L2Npc))
+ {
+ if (_selfAnalysis.hasHealOrResurrect && (cha instanceof L2PcInstance) && ((L2Npc) _actor).getCastle().getSiege().checkIsDefender(((L2PcInstance) cha).getClan()))
+ {
+ // heal friends
+ if (!_actor.isAttackingDisabled() && (cha.getCurrentHp() < (cha.getMaxHp() * 0.6)) && (_actor.getCurrentHp() > (_actor.getMaxHp() / 2)) && (_actor.getCurrentMp() > (_actor.getMaxMp() / 2)) && cha.isInCombat())
+ {
+ for (L2Skill sk : _selfAnalysis.healSkills)
+ {
+ if (_actor.getCurrentMp() < sk.getMpConsume())
+ {
+ continue;
+ }
+ if (_actor.isSkillDisabled(sk))
+ {
+ continue;
+ }
+ if (!Util.checkIfInRange(sk.getCastRange(), _actor, cha, true))
+ {
+ continue;
+ }
+
+ int chance = 5;
+ if (chance >= Rnd.get(100))
+ {
+ continue;
+ }
+ if (!GeoData.getInstance().canSeeTarget(_actor, cha))
+ {
+ break;
+ }
+
+ L2Object OldTarget = _actor.getTarget();
+ _actor.setTarget(cha);
+ clientStopMoving(null);
+ _accessor.doCast(sk);
+ _actor.setTarget(OldTarget);
+ return;
+ }
+ }
+ }
+ continue;
+ }
+
+ L2Npc npc = (L2Npc) cha;
+
+ if (!faction_id.equals(npc.getFactionId()))
+ {
+ continue;
+ }
+
+ if (npc.getAI() != null) // TODO: possibly check not needed
+ {
+ if (!npc.isDead() && (Math.abs(target.getZ() - npc.getZ()) < 600)
+ // && _actor.getAttackByList().contains(getAttackTarget())
+ && ((npc.getAI()._intention == CtrlIntention.AI_INTENTION_IDLE) || (npc.getAI()._intention == CtrlIntention.AI_INTENTION_ACTIVE))
+ // limiting aggro for siege guards
+ && target.isInsideRadius(npc, 1500, true, false) && GeoData.getInstance().canSeeTarget(npc, target))
+ {
+ // Notify the L2Object AI with EVT_AGGRESSION
+ npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, getAttackTarget(), 1);
+ return;
+ }
+ // heal friends
+ if (_selfAnalysis.hasHealOrResurrect && !_actor.isAttackingDisabled() && (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) && (_actor.getCurrentHp() > (_actor.getMaxHp() / 2)) && (_actor.getCurrentMp() > (_actor.getMaxMp() / 2)) && npc.isInCombat())
+ {
+ for (L2Skill sk : _selfAnalysis.healSkills)
+ {
+ if (_actor.getCurrentMp() < sk.getMpConsume())
+ {
+ continue;
+ }
+ if (_actor.isSkillDisabled(sk))
+ {
+ continue;
+ }
+ if (!Util.checkIfInRange(sk.getCastRange(), _actor, npc, true))
+ {
+ continue;
+ }
+
+ int chance = 4;
+ if (chance >= Rnd.get(100))
+ {
+ continue;
+ }
+ if (!GeoData.getInstance().canSeeTarget(_actor, npc))
+ {
+ break;
+ }
+
+ L2Object OldTarget = _actor.getTarget();
+ _actor.setTarget(npc);
+ clientStopMoving(null);
+ _accessor.doCast(sk);
+ _actor.setTarget(OldTarget);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ private void attackPrepare()
+ {
+ // Get all information needed to choose between physical or magical attack
+ L2Skill[] skills = null;
+ double dist_2 = 0;
+ int range = 0;
+ L2DefenderInstance sGuard = (L2DefenderInstance) _actor;
+ L2Character attackTarget = getAttackTarget();
+
+ try
+ {
+ _actor.setTarget(attackTarget);
+ skills = _actor.getAllSkills();
+ dist_2 = _actor.getPlanDistanceSq(attackTarget.getX(), attackTarget.getY());
+ range = _actor.getPhysicalAttackRange() + _actor.getTemplate().collisionRadius + attackTarget.getTemplate().collisionRadius;
+ if (attackTarget.isMoving())
+ {
+ range += 50;
+ }
+ }
+ catch (NullPointerException e)
+ {
+ // _log.warning("AttackableAI: Attack target is NULL.");
+ _actor.setTarget(null);
+ setIntention(AI_INTENTION_IDLE, null, null);
+ return;
+ }
+
+ // never attack defenders
+ if ((attackTarget instanceof L2PcInstance) && sGuard.getCastle().getSiege().checkIsDefender(((L2PcInstance) attackTarget).getClan()))
+ {
+ // Cancel the target
+ sGuard.stopHating(attackTarget);
+ _actor.setTarget(null);
+ setIntention(AI_INTENTION_IDLE, null, null);
+ return;
+ }
+
+ if (!GeoData.getInstance().canSeeTarget(_actor, attackTarget))
+ {
+ // Siege guards differ from normal mobs currently:
+ // If target cannot seen, don't attack any more
+ sGuard.stopHating(attackTarget);
+ _actor.setTarget(null);
+ setIntention(AI_INTENTION_IDLE, null, null);
+ return;
+ }
+
+ // Check if the actor isn't muted and if it is far from target
+ if (!_actor.isMuted() && (dist_2 > (range * range)))
+ {
+ // check for long ranged skills and heal/buff skills
+ for (L2Skill sk : skills)
+ {
+ int castRange = sk.getCastRange();
+
+ if ((dist_2 <= (castRange * castRange)) && (castRange > 70) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() >= _actor.getStat().getMpConsume(sk)) && !sk.isPassive())
+ {
+
+ L2Object OldTarget = _actor.getTarget();
+ if ((sk.getSkillType() == L2SkillType.BUFF) || (sk.getSkillType() == L2SkillType.HEAL))
+ {
+ boolean useSkillSelf = true;
+ if ((sk.getSkillType() == L2SkillType.HEAL) && (_actor.getCurrentHp() > (int) (_actor.getMaxHp() / 1.5)))
+ {
+ useSkillSelf = false;
+ break;
+ }
+ if (sk.getSkillType() == L2SkillType.BUFF)
+ {
+ L2Effect[] effects = _actor.getAllEffects();
+ for (int i = 0; (effects != null) && (i < effects.length); i++)
+ {
+ L2Effect effect = effects[i];
+ if (effect.getSkill() == sk)
+ {
+ useSkillSelf = false;
+ break;
+ }
+ }
+ }
+ if (useSkillSelf)
+ {
+ _actor.setTarget(_actor);
+ }
+ }
+
+ clientStopMoving(null);
+ _accessor.doCast(sk);
+ _actor.setTarget(OldTarget);
+ return;
+ }
+ }
+
+ // Check if the L2SiegeGuardInstance is attacking, knows the target and can't run
+ if (!(_actor.isAttackingNow()) && (_actor.getRunSpeed() == 0) && (_actor.getKnownList().knowsObject(attackTarget)))
+ {
+ // Cancel the target
+ _actor.getKnownList().removeKnownObject(attackTarget);
+ _actor.setTarget(null);
+ setIntention(AI_INTENTION_IDLE, null, null);
+ }
+ else
+ {
+ double dx = _actor.getX() - attackTarget.getX();
+ double dy = _actor.getY() - attackTarget.getY();
+ double dz = _actor.getZ() - attackTarget.getZ();
+ double homeX = attackTarget.getX() - sGuard.getSpawn().getLocx();
+ double homeY = attackTarget.getY() - sGuard.getSpawn().getLocy();
+
+ // Check if the L2SiegeGuardInstance isn't too far from it's home location
+ if ((((dx * dx) + (dy * dy)) > 10000) && (((homeX * homeX) + (homeY * homeY)) > 3240000) // 1800 * 1800
+ && (_actor.getKnownList().knowsObject(attackTarget)))
+ {
+ // Cancel the target
+ _actor.getKnownList().removeKnownObject(attackTarget);
+ _actor.setTarget(null);
+ setIntention(AI_INTENTION_IDLE, null, null);
+ }
+ else
+ // Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn (broadcast)
+ {
+ // Temporary hack for preventing guards jumping off towers,
+ // before replacing this with effective geodata checks and AI modification
+ if ((dz * dz) < (170 * 170)) // normally 130 if guard z coordinates correct
+ {
+ if (_selfAnalysis.isHealer)
+ {
+ return;
+ }
+ if (_selfAnalysis.isMage)
+ {
+ range = _selfAnalysis.maxCastRange - 50;
+ }
+ if (attackTarget.isMoving())
+ {
+ moveToPawn(attackTarget, range - 70);
+ }
+ else
+ {
+ moveToPawn(attackTarget, range);
+ }
+ }
+ }
+ }
+
+ return;
+
+ }
+ // Else, if the actor is muted and far from target, just "move to pawn"
+ else if (_actor.isMuted() && (dist_2 > (range * range)) && !_selfAnalysis.isHealer)
+ {
+ // Temporary hack for preventing guards jumping off towers,
+ // before replacing this with effective geodata checks and AI modification
+ double dz = _actor.getZ() - attackTarget.getZ();
+ if ((dz * dz) < (170 * 170)) // normally 130 if guard z coordinates correct
+ {
+ if (_selfAnalysis.isMage)
+ {
+ range = _selfAnalysis.maxCastRange - 50;
+ }
+ if (attackTarget.isMoving())
+ {
+ moveToPawn(attackTarget, range - 70);
+ }
+ else
+ {
+ moveToPawn(attackTarget, range);
+ }
+ }
+ return;
+ }
+ // Else, if this is close enough to attack
+ else if (dist_2 <= (range * range))
+ {
+ // Force mobs to attack anybody if confused
+ L2Character hated = null;
+ if (_actor.isConfused())
+ {
+ hated = attackTarget;
+ }
+ else
+ {
+ hated = ((L2Attackable) _actor).getMostHated();
+ }
+
+ if (hated == null)
+ {
+ setIntention(AI_INTENTION_ACTIVE, null, null);
+ return;
+ }
+ if (hated != attackTarget)
+ {
+ attackTarget = hated;
+ }
+
+ _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
+
+ // check for close combat skills && heal/buff skills
+ if (!_actor.isMuted() && (Rnd.nextInt(100) <= 5))
+ {
+ for (L2Skill sk : skills)
+ {
+ int castRange = sk.getCastRange();
+
+ if (((castRange * castRange) >= dist_2) && !sk.isPassive() && (_actor.getCurrentMp() >= _actor.getStat().getMpConsume(sk)) && !_actor.isSkillDisabled(sk))
+ {
+ L2Object OldTarget = _actor.getTarget();
+ if ((sk.getSkillType() == L2SkillType.BUFF) || (sk.getSkillType() == L2SkillType.HEAL))
+ {
+ boolean useSkillSelf = true;
+ if ((sk.getSkillType() == L2SkillType.HEAL) && (_actor.getCurrentHp() > (int) (_actor.getMaxHp() / 1.5)))
+ {
+ useSkillSelf = false;
+ break;
+ }
+ if (sk.getSkillType() == L2SkillType.BUFF)
+ {
+ L2Effect[] effects = _actor.getAllEffects();
+ for (int i = 0; (effects != null) && (i < effects.length); i++)
+ {
+ L2Effect effect = effects[i];
+ if (effect.getSkill() == sk)
+ {
+ useSkillSelf = false;
+ break;
+ }
+ }
+ }
+ if (useSkillSelf)
+ {
+ _actor.setTarget(_actor);
+ }
+ }
+
+ clientStopMoving(null);
+ _accessor.doCast(sk);
+ _actor.setTarget(OldTarget);
+ return;
+ }
+ }
+ }
+ // Finally, do the physical attack itself
+ if (!_selfAnalysis.isHealer)
+ {
+ _accessor.doAttack(attackTarget);
+ }
+ }
+ }
+
+ /**
+ * Manage AI thinking actions of a L2Attackable.
+ *
+ */
+ @Override
+ protected void onEvtThink()
+ {
+ // if(getIntention() != AI_INTENTION_IDLE && (!_actor.isVisible() || !_actor.hasAI() || !_actor.isKnownPlayers()))
+ // setIntention(AI_INTENTION_IDLE);
+
+ // Check if the thinking action is already in progress
+ if (_thinking || _actor.isCastingNow() || _actor.isAllSkillsDisabled())
+ {
+ return;
+ }
+
+ // Start thinking action
+ _thinking = true;
+
+ try
+ {
+ // Manage AI thinks of a L2Attackable
+ if (getIntention() == AI_INTENTION_ACTIVE)
+ {
+ thinkActive();
+ }
+ else if (getIntention() == AI_INTENTION_ATTACK)
+ {
+ thinkAttack();
+ }
+ }
+ finally
+ {
+ // Stop thinking action
+ _thinking = false;
+ }
+ }
+
+ /**
+ * Launch actions corresponding to the Event Attacked.
+ *
+ * Actions :
+ *
+ *
Init the attack : Calculate the attack timeout, Set the _globalAggro to 0, Add the attacker to the actor _aggroList
Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
Set the Intention to AI_INTENTION_ATTACK
+ *
+ *
+ * @param attacker The L2Character that attacks the actor
+ */
+ @Override
+ protected void onEvtAttacked(L2Character attacker)
+ {
+ // Calculate the attack timeout
+ _attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
+
+ // Set the _globalAggro to 0 to permit attack even just after spawn
+ if (_globalAggro < 0)
+ {
+ _globalAggro = 0;
+ }
+
+ // Add the attacker to the _aggroList of the actor
+ ((L2Attackable) _actor).addDamageHate(attacker, 0, 1);
+
+ // Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
+ if (!_actor.isRunning())
+ {
+ _actor.setRunning();
+ }
+
+ // Set the Intention to AI_INTENTION_ATTACK
+ if (getIntention() != AI_INTENTION_ATTACK)
+ {
+ setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker, null);
+ }
+
+ super.onEvtAttacked(attacker);
+ }
+
+ /**
+ * Launch actions corresponding to the Event Aggression.
+ *
+ * Actions :
+ *
+ *
Add the target to the actor _aggroList or update hate if already present
Set the actor Intention to AI_INTENTION_ATTACK (if actor is L2GuardInstance check if it isn't too far from its home location)
+ *
+ * @param attacker The L2Character that attacks
+ * @param aggro The value of hate to add to the actor against the target
+ */
+ @Override
+ protected void onEvtAggression(L2Character target, int aggro)
+ {
+ if (_actor == null)
+ {
+ return;
+ }
+ L2Attackable me = (L2Attackable) _actor;
+
+ if (target != null)
+ {
+ // Add the target to the actor _aggroList or update hate if already present
+ me.addDamageHate(target, 0, aggro);
+
+ // Get the hate of the actor against the target
+ aggro = me.getHating(target);
+
+ if (aggro <= 0)
+ {
+ if (me.getMostHated() == null)
+ {
+ _globalAggro = -25;
+ me.clearAggroList();
+ setIntention(AI_INTENTION_IDLE, null, null);
+ }
+ return;
+ }
+
+ // Set the actor AI Intention to AI_INTENTION_ATTACK
+ if (getIntention() != CtrlIntention.AI_INTENTION_ATTACK)
+ {
+ // Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
+ if (!_actor.isRunning())
+ {
+ _actor.setRunning();
+ }
+
+ L2DefenderInstance sGuard = (L2DefenderInstance) _actor;
+ double homeX = target.getX() - sGuard.getSpawn().getLocx();
+ double homeY = target.getY() - sGuard.getSpawn().getLocy();
+
+ // Check if the L2SiegeGuardInstance is not too far from its home location
+ if (((homeX * homeX) + (homeY * homeY)) < 3240000)
+ {
+ setIntention(CtrlIntention.AI_INTENTION_ATTACK, target, null);
+ }
+ }
+ }
+ else
+ {
+ // currently only for setting lower general aggro
+ if (aggro >= 0)
+ {
+ return;
+ }
+
+ L2Character mostHated = me.getMostHated();
+ if (mostHated == null)
+ {
+ _globalAggro = -25;
+ return;
+ }
+ for (L2Character aggroed : me.getAggroList().keySet())
+ {
+ me.addDamageHate(aggroed, 0, aggro);
+ }
+
+ aggro = me.getHating(mostHated);
+ if (aggro <= 0)
+ {
+ _globalAggro = -25;
+ me.clearAggroList();
+ setIntention(AI_INTENTION_IDLE, null, null);
+ }
+ }
+ }
+
+ @Override
+ public void stopAITask()
+ {
+ if (_aiTask != null)
+ {
+ _aiTask.cancel(false);
+ _aiTask = null;
+ }
+ _accessor.detachAI();
+ super.stopAITask();
+ }
+
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/ai/L2SummonAI.java b/L2J_Server/java/com/l2jserver/gameserver/ai/L2SummonAI.java
new file mode 100644
index 00000000..e92cbdfd
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/ai/L2SummonAI.java
@@ -0,0 +1,299 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.ai;
+
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
+import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
+
+import java.util.concurrent.Future;
+
+import com.l2jserver.Config;
+import com.l2jserver.gameserver.GeoData;
+import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.model.L2Object;
+import com.l2jserver.gameserver.model.L2Skill;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.actor.L2Character.AIAccessor;
+import com.l2jserver.gameserver.model.actor.L2Summon;
+import com.l2jserver.util.Rnd;
+
+public class L2SummonAI extends L2PlayableAI implements Runnable
+{
+ private static final int AVOID_RADIUS = 70;
+
+ private volatile boolean _thinking; // to prevent recursive thinking
+ private volatile boolean _startFollow = ((L2Summon) _actor).getFollowStatus();
+ private L2Character _lastAttack = null;
+
+ private volatile boolean _startAvoid = false;
+ private Future> _avoidTask = null;
+
+ public L2SummonAI(AIAccessor accessor)
+ {
+ super(accessor);
+ }
+
+ @Override
+ protected void onIntentionIdle()
+ {
+ stopFollow();
+ _startFollow = false;
+ onIntentionActive();
+ }
+
+ @Override
+ protected void onIntentionActive()
+ {
+ L2Summon summon = (L2Summon) _actor;
+ if (_startFollow)
+ {
+ setIntention(AI_INTENTION_FOLLOW, summon.getOwner());
+ }
+ else
+ {
+ super.onIntentionActive();
+ }
+ }
+
+ @Override
+ synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
+ {
+ switch (intention)
+ {
+ case AI_INTENTION_ACTIVE:
+ case AI_INTENTION_FOLLOW:
+ startAvoidTask();
+ break;
+ default:
+ stopAvoidTask();
+ }
+
+ super.changeIntention(intention, arg0, arg1);
+ }
+
+ private void thinkAttack()
+ {
+ if (checkTargetLostOrDead(getAttackTarget()))
+ {
+ setAttackTarget(null);
+ return;
+ }
+ if (maybeMoveToPawn(getAttackTarget(), _actor.getPhysicalAttackRange()))
+ {
+ return;
+ }
+ clientStopMoving(null);
+ _accessor.doAttack(getAttackTarget());
+ }
+
+ private void thinkCast()
+ {
+ L2Summon summon = (L2Summon) _actor;
+ if (checkTargetLost(getCastTarget()))
+ {
+ setCastTarget(null);
+ return;
+ }
+ boolean val = _startFollow;
+ if (maybeMoveToPawn(getCastTarget(), _actor.getMagicalAttackRange(_skill)))
+ {
+ return;
+ }
+ clientStopMoving(null);
+ summon.setFollowStatus(false);
+ setIntention(AI_INTENTION_IDLE);
+ _startFollow = val;
+ _accessor.doCast(_skill);
+ }
+
+ private void thinkPickUp()
+ {
+ if (checkTargetLost(getTarget()))
+ {
+ return;
+ }
+ if (maybeMoveToPawn(getTarget(), 36))
+ {
+ return;
+ }
+ setIntention(AI_INTENTION_IDLE);
+ ((L2Summon.AIAccessor) _accessor).doPickupItem(getTarget());
+ }
+
+ private void thinkInteract()
+ {
+ if (checkTargetLost(getTarget()))
+ {
+ return;
+ }
+ if (maybeMoveToPawn(getTarget(), 36))
+ {
+ return;
+ }
+ setIntention(AI_INTENTION_IDLE);
+ }
+
+ @Override
+ protected void onEvtThink()
+ {
+ if (_thinking || _actor.isCastingNow() || _actor.isAllSkillsDisabled())
+ {
+ return;
+ }
+ _thinking = true;
+ try
+ {
+ switch (getIntention())
+ {
+ case AI_INTENTION_ATTACK:
+ thinkAttack();
+ break;
+ case AI_INTENTION_CAST:
+ thinkCast();
+ break;
+ case AI_INTENTION_PICK_UP:
+ thinkPickUp();
+ break;
+ case AI_INTENTION_INTERACT:
+ thinkInteract();
+ break;
+ }
+ }
+ finally
+ {
+ _thinking = false;
+ }
+ }
+
+ @Override
+ protected void onEvtFinishCasting()
+ {
+ if (_lastAttack == null)
+ {
+ ((L2Summon) _actor).setFollowStatus(_startFollow);
+ }
+ else
+ {
+ setIntention(CtrlIntention.AI_INTENTION_ATTACK, _lastAttack);
+ _lastAttack = null;
+ }
+ }
+
+ @Override
+ protected void onEvtAttacked(L2Character attacker)
+ {
+ super.onEvtAttacked(attacker);
+
+ avoidAttack(attacker);
+ }
+
+ @Override
+ protected void onEvtEvaded(L2Character attacker)
+ {
+ super.onEvtEvaded(attacker);
+
+ avoidAttack(attacker);
+ }
+
+ private void avoidAttack(L2Character attacker)
+ {
+ // trying to avoid if summon near owner
+ if ((((L2Summon) _actor).getOwner() != null) && (((L2Summon) _actor).getOwner() != attacker) && ((L2Summon) _actor).getOwner().isInsideRadius(_actor, 2 * AVOID_RADIUS, true, false))
+ {
+ _startAvoid = true;
+ }
+ }
+
+ @Override
+ public void run()
+ {
+ if (_startAvoid)
+ {
+ _startAvoid = false;
+
+ if (!_clientMoving && !_actor.isDead() && !_actor.isMovementDisabled())
+ {
+ final int ownerX = ((L2Summon) _actor).getOwner().getX();
+ final int ownerY = ((L2Summon) _actor).getOwner().getY();
+ final double angle = Math.toRadians(Rnd.get(-90, 90)) + Math.atan2(ownerY - _actor.getY(), ownerX - _actor.getX());
+
+ final int targetX = ownerX + (int) (AVOID_RADIUS * Math.cos(angle));
+ final int targetY = ownerY + (int) (AVOID_RADIUS * Math.sin(angle));
+ if ((Config.GEODATA == 0) || GeoData.getInstance().canMoveFromToTarget(_actor.getX(), _actor.getY(), _actor.getZ(), targetX, targetY, _actor.getZ(), _actor.getInstanceId()))
+ {
+ moveTo(targetX, targetY, _actor.getZ());
+ }
+ }
+ }
+ }
+
+ public void notifyFollowStatusChange()
+ {
+ _startFollow = !_startFollow;
+ switch (getIntention())
+ {
+ case AI_INTENTION_ACTIVE:
+ case AI_INTENTION_FOLLOW:
+ case AI_INTENTION_IDLE:
+ case AI_INTENTION_MOVE_TO:
+ case AI_INTENTION_PICK_UP:
+ ((L2Summon) _actor).setFollowStatus(_startFollow);
+ }
+ }
+
+ public void setStartFollowController(boolean val)
+ {
+ _startFollow = val;
+ }
+
+ @Override
+ protected void onIntentionCast(L2Skill skill, L2Object target)
+ {
+ if (getIntention() == AI_INTENTION_ATTACK)
+ {
+ _lastAttack = getAttackTarget();
+ }
+ else
+ {
+ _lastAttack = null;
+ }
+ super.onIntentionCast(skill, target);
+ }
+
+ private void startAvoidTask()
+ {
+ if (_avoidTask == null)
+ {
+ _avoidTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(this, 100, 100);
+ }
+ }
+
+ private void stopAvoidTask()
+ {
+ if (_avoidTask != null)
+ {
+ _avoidTask.cancel(false);
+ _avoidTask = null;
+ }
+ }
+
+ @Override
+ public void stopAITask()
+ {
+ stopAvoidTask();
+ super.stopAITask();
+ }
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/ai/L2VehicleAI.java b/L2J_Server/java/com/l2jserver/gameserver/ai/L2VehicleAI.java
new file mode 100644
index 00000000..90abd015
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/ai/L2VehicleAI.java
@@ -0,0 +1,121 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.ai;
+
+import com.l2jserver.gameserver.model.L2Object;
+import com.l2jserver.gameserver.model.L2Skill;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.actor.L2Vehicle;
+
+public abstract class L2VehicleAI extends L2CharacterAI
+{
+ /**
+ * @author DS Simple AI for vehicles
+ */
+ public L2VehicleAI(L2Vehicle.AIAccessor accessor)
+ {
+ super(accessor);
+ }
+
+ @Override
+ protected void onIntentionAttack(L2Character target)
+ {
+ }
+
+ @Override
+ protected void onIntentionCast(L2Skill skill, L2Object target)
+ {
+ }
+
+ @Override
+ protected void onIntentionFollow(L2Character target)
+ {
+ }
+
+ @Override
+ protected void onIntentionPickUp(L2Object item)
+ {
+ }
+
+ @Override
+ protected void onIntentionInteract(L2Object object)
+ {
+ }
+
+ @Override
+ protected void onEvtAttacked(L2Character attacker)
+ {
+ }
+
+ @Override
+ protected void onEvtAggression(L2Character target, int aggro)
+ {
+ }
+
+ @Override
+ protected void onEvtStunned(L2Character attacker)
+ {
+ }
+
+ @Override
+ protected void onEvtSleeping(L2Character attacker)
+ {
+ }
+
+ @Override
+ protected void onEvtRooted(L2Character attacker)
+ {
+ }
+
+ @Override
+ protected void onEvtForgetObject(L2Object object)
+ {
+ }
+
+ @Override
+ protected void onEvtCancel()
+ {
+ }
+
+ @Override
+ protected void onEvtDead()
+ {
+ }
+
+ @Override
+ protected void onEvtFakeDeath()
+ {
+ }
+
+ @Override
+ protected void onEvtFinishCasting()
+ {
+ }
+
+ @Override
+ protected void clientActionFailed()
+ {
+ }
+
+ @Override
+ protected void moveToPawn(L2Object pawn, int offset)
+ {
+ }
+
+ @Override
+ protected void clientStoppedMoving()
+ {
+ }
+}
\ No newline at end of file
diff --git a/L2J_Server/java/com/l2jserver/gameserver/cache/CrestCache.java b/L2J_Server/java/com/l2jserver/gameserver/cache/CrestCache.java
new file mode 100644
index 00000000..0ec4dfaa
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/cache/CrestCache.java
@@ -0,0 +1,321 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.cache;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javolution.util.FastMap;
+
+import com.l2jserver.Config;
+import com.l2jserver.L2DatabaseFactory;
+import com.l2jserver.gameserver.datatables.ClanTable;
+import com.l2jserver.gameserver.idfactory.IdFactory;
+import com.l2jserver.gameserver.model.L2Clan;
+
+/**
+ * @author Layane
+ */
+public class CrestCache
+{
+ private static Logger _log = Logger.getLogger(CrestCache.class.getName());
+
+ private final FastMRUCache _cachePledge = new FastMRUCache<>();
+
+ private final FastMRUCache _cachePledgeLarge = new FastMRUCache<>();
+
+ private final FastMRUCache _cacheAlly = new FastMRUCache<>();
+
+ private int _loadedFiles;
+
+ private long _bytesBuffLen;
+
+ public static CrestCache getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ private CrestCache()
+ {
+ convertOldPedgeFiles();
+ reload();
+ }
+
+ public void reload()
+ {
+ FileFilter filter = new BmpFilter();
+
+ File dir = new File(Config.DATAPACK_ROOT, "data/crests/");
+
+ File[] files = dir.listFiles(filter);
+ byte[] content;
+ synchronized (this)
+ {
+ _loadedFiles = 0;
+ _bytesBuffLen = 0;
+
+ _cachePledge.clear();
+ _cachePledgeLarge.clear();
+ _cacheAlly.clear();
+ }
+
+ FastMap _mapPledge = _cachePledge.getContentMap();
+ FastMap _mapPledgeLarge = _cachePledgeLarge.getContentMap();
+ FastMap _mapAlly = _cacheAlly.getContentMap();
+
+ for (File file : files)
+ {
+
+ synchronized (this)
+ {
+ try (RandomAccessFile f = new RandomAccessFile(file, "r"))
+ {
+ content = new byte[(int) f.length()];
+ f.readFully(content);
+
+ if (file.getName().startsWith("Crest_Large_"))
+ {
+ _mapPledgeLarge.put(Integer.valueOf(file.getName().substring(12, file.getName().length() - 4)), content);
+ }
+ else if (file.getName().startsWith("Crest_"))
+ {
+ _mapPledge.put(Integer.valueOf(file.getName().substring(6, file.getName().length() - 4)), content);
+ }
+ else if (file.getName().startsWith("AllyCrest_"))
+ {
+ _mapAlly.put(Integer.valueOf(file.getName().substring(10, file.getName().length() - 4)), content);
+ }
+ _loadedFiles++;
+ _bytesBuffLen += content.length;
+ }
+ catch (Exception e)
+ {
+ _log.log(Level.WARNING, "Problem with crest bmp file " + e.getMessage(), e);
+ }
+ }
+ }
+
+ _log.info("Cache[Crest]: " + String.format("%.3f", getMemoryUsage()) + "MB on " + getLoadedFiles() + " files loaded. (Forget Time: " + (_cachePledge.getForgetTime() / 1000) + "s , Capacity: " + _cachePledge.capacity() + ")");
+ }
+
+ public void convertOldPedgeFiles()
+ {
+ File dir = new File(Config.DATAPACK_ROOT, "data/crests/");
+
+ File[] files = dir.listFiles(new OldPledgeFilter());
+
+ for (File file : files)
+ {
+ int clanId = Integer.parseInt(file.getName().substring(7, file.getName().length() - 4));
+
+ _log.info("Found old crest file \"" + file.getName() + "\" for clanId " + clanId);
+
+ int newId = IdFactory.getInstance().getNextId();
+
+ L2Clan clan = ClanTable.getInstance().getClan(clanId);
+
+ if (clan != null)
+ {
+ removeOldPledgeCrest(clan.getCrestId());
+
+ file.renameTo(new File(Config.DATAPACK_ROOT, "data/crests/Crest_" + newId + ".bmp"));
+ _log.info("Renamed Clan crest to new format: Crest_" + newId + ".bmp");
+
+ Connection con = null;
+
+ try
+ {
+ con = L2DatabaseFactory.getInstance().getConnection();
+ PreparedStatement statement = con.prepareStatement("UPDATE clan_data SET crest_id = ? WHERE clan_id = ?");
+ statement.setInt(1, newId);
+ statement.setInt(2, clan.getClanId());
+ statement.executeUpdate();
+ statement.close();
+ }
+ catch (SQLException e)
+ {
+ _log.log(Level.WARNING, "Could not update the crest id:" + e.getMessage(), e);
+ }
+ finally
+ {
+ L2DatabaseFactory.close(con);
+ }
+
+ clan.setCrestId(newId);
+ }
+ else
+ {
+ _log.info("Clan Id: " + clanId + " does not exist in table.. deleting.");
+ file.delete();
+ }
+ }
+ }
+
+ public float getMemoryUsage()
+ {
+ return ((float) _bytesBuffLen / 1048576);
+ }
+
+ public int getLoadedFiles()
+ {
+ return _loadedFiles;
+ }
+
+ public byte[] getPledgeCrest(int id)
+ {
+ return _cachePledge.get(id);
+ }
+
+ public byte[] getPledgeCrestLarge(int id)
+ {
+ return _cachePledgeLarge.get(id);
+ }
+
+ public byte[] getAllyCrest(int id)
+ {
+ return _cacheAlly.get(id);
+ }
+
+ public void removePledgeCrest(int id)
+ {
+ File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/Crest_" + id + ".bmp");
+ _cachePledge.remove(id);
+ try
+ {
+ crestFile.delete();
+ }
+ catch (Exception e)
+ {
+ }
+ }
+
+ public void removePledgeCrestLarge(int id)
+ {
+ File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/Crest_Large_" + id + ".bmp");
+ _cachePledgeLarge.remove(id);
+ try
+ {
+ crestFile.delete();
+ }
+ catch (Exception e)
+ {
+ }
+ }
+
+ public void removeOldPledgeCrest(int id)
+ {
+ File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/Pledge_" + id + ".bmp");
+ try
+ {
+ crestFile.delete();
+ }
+ catch (Exception e)
+ {
+ }
+ }
+
+ public void removeAllyCrest(int id)
+ {
+ File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/AllyCrest_" + id + ".bmp");
+ _cacheAlly.remove(id);
+ try
+ {
+ crestFile.delete();
+ }
+ catch (Exception e)
+ {
+ }
+ }
+
+ public boolean savePledgeCrest(int newId, byte[] data)
+ {
+ File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/Crest_" + newId + ".bmp");
+ try (FileOutputStream out = new FileOutputStream(crestFile))
+ {
+ out.write(data);
+ _cachePledge.getContentMap().put(newId, data);
+ return true;
+ }
+ catch (IOException e)
+ {
+ _log.log(Level.INFO, "Error saving pledge crest" + crestFile + ":", e);
+ return false;
+ }
+ }
+
+ public boolean savePledgeCrestLarge(int newId, byte[] data)
+ {
+ File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/Crest_Large_" + newId + ".bmp");
+ try (FileOutputStream out = new FileOutputStream(crestFile))
+ {
+ out.write(data);
+ _cachePledgeLarge.getContentMap().put(newId, data);
+ return true;
+ }
+ catch (IOException e)
+ {
+ _log.log(Level.INFO, "Error saving Large pledge crest" + crestFile + ":", e);
+ return false;
+ }
+ }
+
+ public boolean saveAllyCrest(int newId, byte[] data)
+ {
+ File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/AllyCrest_" + newId + ".bmp");
+ try (FileOutputStream out = new FileOutputStream(crestFile))
+ {
+ out.write(data);
+ _cacheAlly.getContentMap().put(newId, data);
+ return true;
+ }
+ catch (IOException e)
+ {
+ _log.log(Level.INFO, "Error saving ally crest" + crestFile + ":", e);
+ return false;
+ }
+ }
+
+ protected static class BmpFilter implements FileFilter
+ {
+ @Override
+ public boolean accept(File file)
+ {
+ return (file.getName().endsWith(".bmp"));
+ }
+ }
+
+ protected static class OldPledgeFilter implements FileFilter
+ {
+ @Override
+ public boolean accept(File file)
+ {
+ return (file.getName().startsWith("Pledge_"));
+ }
+ }
+
+ @SuppressWarnings("synthetic-access")
+ private static class SingletonHolder
+ {
+ protected static final CrestCache _instance = new CrestCache();
+ }
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/cache/FastMRUCache.java b/L2J_Server/java/com/l2jserver/gameserver/cache/FastMRUCache.java
new file mode 100644
index 00000000..2f7835d0
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/cache/FastMRUCache.java
@@ -0,0 +1,226 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.cache;
+
+import javolution.context.ObjectFactory;
+import javolution.lang.Reusable;
+import javolution.util.FastCollection;
+import javolution.util.FastComparator;
+import javolution.util.FastList;
+import javolution.util.FastMap;
+
+/**
+ * @author Layane
+ */
+@SuppressWarnings(
+{
+ "rawtypes"
+})
+public class FastMRUCache extends FastCollection implements Reusable
+{
+ /**
+ * Comment for serialVersionUID
+ */
+ private static final long serialVersionUID = 1L;
+ private static final int DEFAULT_CAPACITY = 50;
+ private static final int DEFAULT_FORGET_TIME = 300000; // 5 Minutes
+
+ private final FastMap _cache = new FastMap().setKeyComparator(FastComparator.DIRECT);
+ private FastMap _map;
+ private final FastList _mruList = new FastList<>();
+ private int _cacheSize;
+ private int _forgetTime;
+
+ class CacheNode
+ {
+ long _lastModified;
+ V _node;
+
+ public CacheNode(V object)
+ {
+ _lastModified = System.currentTimeMillis();
+ _node = object;
+ }
+
+ @Override
+ public boolean equals(Object object)
+ {
+ return _node == object;
+ }
+
+ }
+
+ /**
+ * Holds the set factory.
+ */
+ private static final ObjectFactory FACTORY = new ObjectFactory()
+ {
+
+ @Override
+ public Object create()
+ {
+ return new FastMRUCache();
+ }
+
+ @Override
+ public void cleanup(Object obj)
+ {
+ ((FastMRUCache) obj).reset();
+ }
+ };
+
+ /**
+ * Returns a set allocated from the stack when executing in a {@link javolution.realtime.PoolContext PoolContext}).
+ * @return a new, pre-allocated or recycled set instance.
+ */
+ public static FastMRUCache newInstance()
+ {
+ return (FastMRUCache) FACTORY.object();
+ }
+
+ public FastMRUCache()
+ {
+ this(new FastMap(), DEFAULT_CAPACITY, DEFAULT_FORGET_TIME);
+ }
+
+ public FastMRUCache(FastMap map)
+ {
+ this(map, DEFAULT_CAPACITY, DEFAULT_FORGET_TIME);
+ }
+
+ public FastMRUCache(FastMap map, int max)
+ {
+ this(map, max, DEFAULT_FORGET_TIME);
+ }
+
+ public FastMRUCache(FastMap map, int max, int forgetTime)
+ {
+ _map = map;
+ _cacheSize = max;
+ _forgetTime = forgetTime;
+ _map.setKeyComparator(FastComparator.DIRECT);
+ }
+
+ // Implements Reusable.
+ @Override
+ public synchronized void reset()
+ {
+ _map.reset();
+ _cache.reset();
+ _mruList.reset();
+ _map.setKeyComparator(FastComparator.DIRECT);
+ _cache.setKeyComparator(FastComparator.DIRECT);
+ }
+
+ public synchronized V get(K key)
+ {
+ V result;
+
+ if (!_cache.containsKey(key))
+ {
+ if (_mruList.size() >= _cacheSize)
+ {
+
+ _cache.remove(_mruList.getLast());
+ _mruList.removeLast();
+ }
+
+ result = _map.get(key);
+
+ _cache.put(key, new CacheNode(result));
+ _mruList.addFirst(key);
+ }
+ else
+ {
+ CacheNode current = _cache.get(key);
+
+ if ((current._lastModified + _forgetTime) <= System.currentTimeMillis())
+ {
+ current._lastModified = System.currentTimeMillis();
+ current._node = _map.get(key);
+ _cache.put(key, current);
+ }
+
+ _mruList.remove(key);
+ _mruList.addFirst(key);
+
+ result = current._node;
+ }
+
+ return result;
+ }
+
+ @Override
+ public synchronized boolean remove(Object key)
+ {
+ _cache.remove(key);
+ _mruList.remove(key);
+ return _map.remove(key) == key;
+ }
+
+ public FastMap getContentMap()
+ {
+ return _map;
+ }
+
+ @Override
+ public int size()
+ {
+ return _mruList.size();
+ }
+
+ public int capacity()
+ {
+ return _cacheSize;
+ }
+
+ public int getForgetTime()
+ {
+ return _forgetTime;
+ }
+
+ @Override
+ public synchronized void clear()
+ {
+ _cache.clear();
+ _mruList.clear();
+ _map.clear();
+ }
+
+ // Implements FastCollection abstract method.
+ @Override
+ public final Record head()
+ {
+ return _mruList.head();
+ }
+
+ @Override
+ public final Record tail()
+ {
+ return _mruList.tail();
+ }
+
+ @Override
+ public final Object valueOf(Record record)
+ {
+ return ((FastMap.Entry) record).getKey();
+ }
+
+ @Override
+ public final void delete(Record record)
+ {
+ remove(((FastMap.Entry) record).getKey());
+ }
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/cache/HtmCache.java b/L2J_Server/java/com/l2jserver/gameserver/cache/HtmCache.java
new file mode 100644
index 00000000..e5821b49
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/cache/HtmCache.java
@@ -0,0 +1,255 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.cache;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileInputStream;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javolution.util.FastMap;
+
+import com.l2jserver.Config;
+import com.l2jserver.gameserver.util.Util;
+
+/**
+ * @author Layane
+ */
+public class HtmCache
+{
+ private static Logger _log = Logger.getLogger(HtmCache.class.getName());
+
+ private final Map _cache;
+
+ private int _loadedFiles;
+ private long _bytesBuffLen;
+
+ public static HtmCache getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ private HtmCache()
+ {
+ if (Config.LAZY_CACHE)
+ {
+ _cache = new FastMap().shared();
+ }
+ else
+ {
+ _cache = new FastMap<>();
+ }
+ reload();
+ }
+
+ public void reload()
+ {
+ reload(Config.DATAPACK_ROOT);
+ }
+
+ public void reload(File f)
+ {
+ if (!Config.LAZY_CACHE)
+ {
+ _log.info("Html cache start...");
+ parseDir(f);
+ _log.info("Cache[HTML]: " + String.format("%.3f", getMemoryUsage()) + " megabytes on " + getLoadedFiles() + " files loaded");
+ }
+ else
+ {
+ _cache.clear();
+ _loadedFiles = 0;
+ _bytesBuffLen = 0;
+ _log.info("Cache[HTML]: Running lazy cache");
+ }
+ }
+
+ public void reloadPath(File f)
+ {
+ parseDir(f);
+ _log.info("Cache[HTML]: Reloaded specified path.");
+ }
+
+ public double getMemoryUsage()
+ {
+ return ((float) _bytesBuffLen / 1048576);
+ }
+
+ public int getLoadedFiles()
+ {
+ return _loadedFiles;
+ }
+
+ protected static class HtmFilter implements FileFilter
+ {
+ @Override
+ public boolean accept(File file)
+ {
+ if (!file.isDirectory())
+ {
+ return (file.getName().endsWith(".htm") || file.getName().endsWith(".html"));
+ }
+ return true;
+ }
+ }
+
+ private void parseDir(File dir)
+ {
+ FileFilter filter = new HtmFilter();
+ File[] files = dir.listFiles(filter);
+
+ for (File file : files)
+ {
+ if (!file.isDirectory())
+ {
+ loadFile(file);
+ }
+ else
+ {
+ parseDir(file);
+ }
+ }
+ }
+
+ public String loadFile(File file)
+ {
+ final String relpath = Util.getRelativePath(Config.DATAPACK_ROOT, file);
+ final int hashcode = relpath.hashCode();
+
+ final HtmFilter filter = new HtmFilter();
+
+ if (file.exists() && filter.accept(file) && !file.isDirectory())
+ {
+ String content;
+ try (FileInputStream fis = new FileInputStream(file);
+ BufferedInputStream bis = new BufferedInputStream(fis))
+ {
+ int bytes = bis.available();
+ byte[] raw = new byte[bytes];
+
+ bis.read(raw);
+ content = new String(raw, "UTF-8");
+ content = content.replaceAll("\r\n", "\n");
+
+ String oldContent = _cache.get(hashcode);
+
+ if (oldContent == null)
+ {
+ _bytesBuffLen += bytes;
+ _loadedFiles++;
+ }
+ else
+ {
+ _bytesBuffLen = (_bytesBuffLen - oldContent.length()) + bytes;
+ }
+
+ _cache.put(hashcode, content);
+
+ return content;
+ }
+ catch (Exception e)
+ {
+ _log.log(Level.WARNING, "Problem with htm file " + e.getMessage(), e);
+ }
+ }
+
+ return null;
+ }
+
+ public String getHtmForce(String prefix, String path)
+ {
+ String content = getHtm(prefix, path);
+
+ if (content == null)
+ {
+ content = "My text is missing: " + path + "";
+ _log.warning("Cache[HTML]: Missing HTML page: " + path);
+ }
+
+ return content;
+ }
+
+ public String getHtm(String prefix, String path)
+ {
+ String newPath = null;
+ String content;
+ if ((prefix != null) && !prefix.isEmpty())
+ {
+ newPath = prefix + path;
+ content = getHtm(newPath);
+ if (content != null)
+ {
+ return content;
+ }
+ }
+
+ content = getHtm(path);
+ if ((content != null) && (newPath != null))
+ {
+ _cache.put(newPath.hashCode(), content);
+ }
+
+ return content;
+ }
+
+ private String getHtm(String path)
+ {
+ if ((path == null) || path.isEmpty())
+ {
+ return ""; // avoid possible NPE
+ }
+
+ final int hashCode = path.hashCode();
+ String content = _cache.get(hashCode);
+
+ if (Config.LAZY_CACHE && (content == null))
+ {
+ content = loadFile(new File(Config.DATAPACK_ROOT, path));
+ }
+
+ return content;
+ }
+
+ public boolean contains(String path)
+ {
+ return _cache.containsKey(path.hashCode());
+ }
+
+ /**
+ * Check if an HTM exists and can be loaded
+ * @param path The path to the HTM
+ */
+ public boolean isLoadable(String path)
+ {
+ File file = new File(path);
+ HtmFilter filter = new HtmFilter();
+
+ if (file.exists() && filter.accept(file) && !file.isDirectory())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ @SuppressWarnings("synthetic-access")
+ private static class SingletonHolder
+ {
+ protected static final HtmCache _instance = new HtmCache();
+ }
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/cache/WarehouseCacheManager.java b/L2J_Server/java/com/l2jserver/gameserver/cache/WarehouseCacheManager.java
new file mode 100644
index 00000000..448dbb30
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/cache/WarehouseCacheManager.java
@@ -0,0 +1,75 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.cache;
+
+import javolution.util.FastMap;
+
+import com.l2jserver.Config;
+import com.l2jserver.gameserver.ThreadPoolManager;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+
+/**
+ * @author -Nemesiss-
+ */
+public class WarehouseCacheManager
+{
+ protected final FastMap _cachedWh;
+ protected final long _cacheTime;
+
+ public static WarehouseCacheManager getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ private WarehouseCacheManager()
+ {
+ _cacheTime = Config.WAREHOUSE_CACHE_TIME * 60000L; // 60*1000 = 60000
+ _cachedWh = new FastMap().shared();
+ ThreadPoolManager.getInstance().scheduleAiAtFixedRate(new CacheScheduler(), 120000, 60000);
+ }
+
+ public void addCacheTask(L2PcInstance pc)
+ {
+ _cachedWh.put(pc, System.currentTimeMillis());
+ }
+
+ public void remCacheTask(L2PcInstance pc)
+ {
+ _cachedWh.remove(pc);
+ }
+
+ public class CacheScheduler implements Runnable
+ {
+ @Override
+ public void run()
+ {
+ long cTime = System.currentTimeMillis();
+ for (L2PcInstance pc : _cachedWh.keySet())
+ {
+ if ((cTime - _cachedWh.get(pc)) > _cacheTime)
+ {
+ pc.clearWarehouse();
+ _cachedWh.remove(pc);
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("synthetic-access")
+ private static class SingletonHolder
+ {
+ protected static final WarehouseCacheManager _instance = new WarehouseCacheManager();
+ }
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/communitybbs/BB/Forum.java b/L2J_Server/java/com/l2jserver/gameserver/communitybbs/BB/Forum.java
new file mode 100644
index 00000000..c7a4e34d
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/communitybbs/BB/Forum.java
@@ -0,0 +1,299 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.communitybbs.BB;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javolution.util.FastList;
+import javolution.util.FastMap;
+
+import com.l2jserver.L2DatabaseFactory;
+import com.l2jserver.gameserver.communitybbs.Manager.ForumsBBSManager;
+import com.l2jserver.gameserver.communitybbs.Manager.TopicBBSManager;
+
+public class Forum
+{
+ // type
+ public static final int ROOT = 0;
+ public static final int NORMAL = 1;
+ public static final int CLAN = 2;
+ public static final int MEMO = 3;
+ public static final int MAIL = 4;
+ // perm
+ public static final int INVISIBLE = 0;
+ public static final int ALL = 1;
+ public static final int CLANMEMBERONLY = 2;
+ public static final int OWNERONLY = 3;
+
+ private static Logger _log = Logger.getLogger(Forum.class.getName());
+ private final List _children;
+ private final Map _topic;
+ private final int _forumId;
+ private String _forumName;
+ // private int _ForumParent;
+ private int _forumType;
+ private int _forumPost;
+ private int _forumPerm;
+ private final Forum _fParent;
+ private int _ownerID;
+ private boolean _loaded = false;
+
+ /**
+ * Creates new instance of Forum. When you create new forum, use {@link com.l2jserver.gameserver.communitybbs.Manager.ForumsBBSManager# addForum(com.l2jserver.gameserver.communitybbs.BB.Forum)} to add forum to the forums manager.
+ * @param i
+ */
+ public Forum(int Forumid, Forum FParent)
+ {
+ _forumId = Forumid;
+ _fParent = FParent;
+ _children = new FastList<>();
+ _topic = new FastMap<>();
+
+ /*
+ * load(); getChildren();
+ */
+ }
+
+ /**
+ * @param name
+ * @param parent
+ * @param type
+ * @param perm
+ */
+ public Forum(String name, Forum parent, int type, int perm, int OwnerID)
+ {
+ _forumName = name;
+ _forumId = ForumsBBSManager.getInstance().getANewID();
+ // _ForumParent = parent.getID();
+ _forumType = type;
+ _forumPost = 0;
+ _forumPerm = perm;
+ _fParent = parent;
+ _ownerID = OwnerID;
+ _children = new FastList<>();
+ _topic = new FastMap<>();
+ parent._children.add(this);
+ ForumsBBSManager.getInstance().addForum(this);
+ _loaded = true;
+ }
+
+ /**
+ *
+ */
+ private void load()
+ {
+ Connection con = null;
+ try
+ {
+ con = L2DatabaseFactory.getInstance().getConnection();
+ PreparedStatement statement = con.prepareStatement("SELECT * FROM forums WHERE forum_id=?");
+ statement.setInt(1, _forumId);
+ ResultSet result = statement.executeQuery();
+
+ if (result.next())
+ {
+ _forumName = result.getString("forum_name");
+ // _ForumParent = result.getInt("forum_parent");
+ _forumPost = result.getInt("forum_post");
+ _forumType = result.getInt("forum_type");
+ _forumPerm = result.getInt("forum_perm");
+ _ownerID = result.getInt("forum_owner_id");
+ }
+ result.close();
+ statement.close();
+ }
+ catch (Exception e)
+ {
+ _log.log(Level.WARNING, "Data error on Forum " + _forumId + " : " + e.getMessage(), e);
+ }
+ finally
+ {
+ L2DatabaseFactory.close(con);
+ }
+ try
+ {
+ con = L2DatabaseFactory.getInstance().getConnection();
+ PreparedStatement statement = con.prepareStatement("SELECT * FROM topic WHERE topic_forum_id=? ORDER BY topic_id DESC");
+ statement.setInt(1, _forumId);
+ ResultSet result = statement.executeQuery();
+
+ while (result.next())
+ {
+ Topic t = new Topic(Topic.ConstructorType.RESTORE, result.getInt("topic_id"), result.getInt("topic_forum_id"), result.getString("topic_name"), result.getLong("topic_date"), result.getString("topic_ownername"), result.getInt("topic_ownerid"), result.getInt("topic_type"), result.getInt("topic_reply"));
+ _topic.put(t.getID(), t);
+ if (t.getID() > TopicBBSManager.getInstance().getMaxID(this))
+ {
+ TopicBBSManager.getInstance().setMaxID(t.getID(), this);
+ }
+ }
+ result.close();
+ statement.close();
+ }
+ catch (Exception e)
+ {
+ _log.log(Level.WARNING, "Data error on Forum " + _forumId + " : " + e.getMessage(), e);
+ }
+ finally
+ {
+ L2DatabaseFactory.close(con);
+ }
+ }
+
+ /**
+ *
+ */
+ private void getChildren()
+ {
+ Connection con = null;
+ try
+ {
+ con = L2DatabaseFactory.getInstance().getConnection();
+ PreparedStatement statement = con.prepareStatement("SELECT forum_id FROM forums WHERE forum_parent=?");
+ statement.setInt(1, _forumId);
+ ResultSet result = statement.executeQuery();
+
+ while (result.next())
+ {
+ Forum f = new Forum(result.getInt("forum_id"), this);
+ _children.add(f);
+ ForumsBBSManager.getInstance().addForum(f);
+ }
+ result.close();
+ statement.close();
+ }
+ catch (Exception e)
+ {
+ _log.log(Level.WARNING, "Data error on Forum (children): " + e.getMessage(), e);
+ }
+ finally
+ {
+ L2DatabaseFactory.close(con);
+ }
+
+ }
+
+ public int getTopicSize()
+ {
+ vload();
+ return _topic.size();
+ }
+
+ public Topic getTopic(int j)
+ {
+ vload();
+ return _topic.get(j);
+ }
+
+ public void addTopic(Topic t)
+ {
+ vload();
+ _topic.put(t.getID(), t);
+ }
+
+ /**
+ * @return
+ */
+ public int getID()
+ {
+ return _forumId;
+ }
+
+ public String getName()
+ {
+ vload();
+ return _forumName;
+ }
+
+ public int getType()
+ {
+ vload();
+ return _forumType;
+ }
+
+ /**
+ * @param name
+ * @return
+ */
+ public Forum getChildByName(String name)
+ {
+ vload();
+ for (Forum f : _children)
+ {
+ if (f.getName().equals(name))
+ {
+ return f;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param id
+ */
+ public void rmTopicByID(int id)
+ {
+ _topic.remove(id);
+
+ }
+
+ /**
+ *
+ */
+ public void insertIntoDb()
+ {
+ Connection con = null;
+ try
+ {
+ con = L2DatabaseFactory.getInstance().getConnection();
+ PreparedStatement statement = con.prepareStatement("INSERT INTO forums (forum_id,forum_name,forum_parent,forum_post,forum_type,forum_perm,forum_owner_id) VALUES (?,?,?,?,?,?,?)");
+ statement.setInt(1, _forumId);
+ statement.setString(2, _forumName);
+ statement.setInt(3, _fParent.getID());
+ statement.setInt(4, _forumPost);
+ statement.setInt(5, _forumType);
+ statement.setInt(6, _forumPerm);
+ statement.setInt(7, _ownerID);
+ statement.execute();
+ statement.close();
+ }
+ catch (Exception e)
+ {
+ _log.log(Level.WARNING, "Error while saving new Forum to db " + e.getMessage(), e);
+ }
+ finally
+ {
+ L2DatabaseFactory.close(con);
+ }
+ }
+
+ /**
+ *
+ */
+ public void vload()
+ {
+ if (_loaded == false)
+ {
+ load();
+ getChildren();
+ _loaded = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/L2J_Server/java/com/l2jserver/gameserver/communitybbs/BB/Post.java b/L2J_Server/java/com/l2jserver/gameserver/communitybbs/BB/Post.java
new file mode 100644
index 00000000..aaf3bf39
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/communitybbs/BB/Post.java
@@ -0,0 +1,205 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.communitybbs.BB;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javolution.util.FastList;
+
+import com.l2jserver.L2DatabaseFactory;
+import com.l2jserver.gameserver.communitybbs.Manager.PostBBSManager;
+
+/**
+ * @author Maktakien
+ */
+public class Post
+{
+ private static Logger _log = Logger.getLogger(Post.class.getName());
+
+ public static class CPost
+ {
+ public int postId;
+ public String postOwner;
+ public int postOwnerId;
+ public long postDate;
+ public int postTopicId;
+ public int postForumId;
+ public String postTxt;
+ }
+
+ private final List _post;
+
+ /**
+ * @param restore
+ * @param t
+ */
+ // public enum ConstructorType {REPLY, CREATE };
+ public Post(String _PostOwner, int _PostOwnerID, long date, int tid, int _PostForumID, String txt)
+ {
+ _post = new FastList<>();
+ CPost cp = new CPost();
+ cp.postId = 0;
+ cp.postOwner = _PostOwner;
+ cp.postOwnerId = _PostOwnerID;
+ cp.postDate = date;
+ cp.postTopicId = tid;
+ cp.postForumId = _PostForumID;
+ cp.postTxt = txt;
+ _post.add(cp);
+ insertindb(cp);
+
+ }
+
+ public void insertindb(CPost cp)
+ {
+ Connection con = null;
+ try
+ {
+ con = L2DatabaseFactory.getInstance().getConnection();
+ PreparedStatement statement = con.prepareStatement("INSERT INTO posts (post_id,post_owner_name,post_ownerid,post_date,post_topic_id,post_forum_id,post_txt) values (?,?,?,?,?,?,?)");
+ statement.setInt(1, cp.postId);
+ statement.setString(2, cp.postOwner);
+ statement.setInt(3, cp.postOwnerId);
+ statement.setLong(4, cp.postDate);
+ statement.setInt(5, cp.postTopicId);
+ statement.setInt(6, cp.postForumId);
+ statement.setString(7, cp.postTxt);
+ statement.execute();
+ statement.close();
+ }
+ catch (Exception e)
+ {
+ _log.log(Level.WARNING, "Error while saving new Post to db " + e.getMessage(), e);
+ }
+ finally
+ {
+ L2DatabaseFactory.close(con);
+ }
+
+ }
+
+ public Post(Topic t)
+ {
+ _post = new FastList<>();
+ load(t);
+ }
+
+ public CPost getCPost(int id)
+ {
+ int i = 0;
+ for (CPost cp : _post)
+ {
+ if (i++ == id)
+ {
+ return cp;
+ }
+ }
+ return null;
+ }
+
+ public void deleteme(Topic t)
+ {
+ PostBBSManager.getInstance().delPostByTopic(t);
+ Connection con = null;
+ try
+ {
+ con = L2DatabaseFactory.getInstance().getConnection();
+ PreparedStatement statement = con.prepareStatement("DELETE FROM posts WHERE post_forum_id=? AND post_topic_id=?");
+ statement.setInt(1, t.getForumID());
+ statement.setInt(2, t.getID());
+ statement.execute();
+ statement.close();
+ }
+ catch (Exception e)
+ {
+ _log.log(Level.WARNING, "Error while deleting post: " + e.getMessage(), e);
+ }
+ finally
+ {
+ L2DatabaseFactory.close(con);
+ }
+ }
+
+ /**
+ * @param t
+ */
+ private void load(Topic t)
+ {
+ Connection con = null;
+ try
+ {
+ con = L2DatabaseFactory.getInstance().getConnection();
+ PreparedStatement statement = con.prepareStatement("SELECT * FROM posts WHERE post_forum_id=? AND post_topic_id=? ORDER BY post_id ASC");
+ statement.setInt(1, t.getForumID());
+ statement.setInt(2, t.getID());
+ ResultSet result = statement.executeQuery();
+ while (result.next())
+ {
+ CPost cp = new CPost();
+ cp.postId = result.getInt("post_id");
+ cp.postOwner = result.getString("post_owner_name");
+ cp.postOwnerId = result.getInt("post_ownerid");
+ cp.postDate = result.getLong("post_date");
+ cp.postTopicId = result.getInt("post_topic_id");
+ cp.postForumId = result.getInt("post_forum_id");
+ cp.postTxt = result.getString("post_txt");
+ _post.add(cp);
+ }
+ result.close();
+ statement.close();
+ }
+ catch (Exception e)
+ {
+ _log.log(Level.WARNING, "Data error on Post " + t.getForumID() + "/" + t.getID() + " : " + e.getMessage(), e);
+ }
+ finally
+ {
+ L2DatabaseFactory.close(con);
+ }
+ }
+
+ /**
+ * @param i
+ */
+ public void updatetxt(int i)
+ {
+ Connection con = null;
+ try
+ {
+ CPost cp = getCPost(i);
+ con = L2DatabaseFactory.getInstance().getConnection();
+ PreparedStatement statement = con.prepareStatement("UPDATE posts SET post_txt=? WHERE post_id=? AND post_topic_id=? AND post_forum_id=?");
+ statement.setString(1, cp.postTxt);
+ statement.setInt(2, cp.postId);
+ statement.setInt(3, cp.postTopicId);
+ statement.setInt(4, cp.postForumId);
+ statement.execute();
+ statement.close();
+ }
+ catch (Exception e)
+ {
+ _log.log(Level.WARNING, "Error while saving new Post to db " + e.getMessage(), e);
+ }
+ finally
+ {
+ L2DatabaseFactory.close(con);
+ }
+ }
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/communitybbs/BB/Topic.java b/L2J_Server/java/com/l2jserver/gameserver/communitybbs/BB/Topic.java
new file mode 100644
index 00000000..c2d92ae9
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/communitybbs/BB/Topic.java
@@ -0,0 +1,170 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.communitybbs.BB;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.l2jserver.L2DatabaseFactory;
+import com.l2jserver.gameserver.communitybbs.Manager.TopicBBSManager;
+
+public class Topic
+{
+
+ private static Logger _log = Logger.getLogger(Topic.class.getName());
+ public static final int MORMAL = 0;
+ public static final int MEMO = 1;
+
+ private final int _id;
+ private final int _forumId;
+ private final String _topicName;
+ private final long _date;
+ private final String _ownerName;
+ private final int _ownerId;
+ private final int _type;
+ private final int _cReply;
+
+ /**
+ * @param restaure
+ * @param i
+ * @param j
+ * @param string
+ * @param k
+ * @param string2
+ * @param l
+ * @param m
+ * @param n
+ */
+ public Topic(ConstructorType ct, int id, int fid, String name, long date, String oname, int oid, int type, int Creply)
+ {
+ _id = id;
+ _forumId = fid;
+ _topicName = name;
+ _date = date;
+ _ownerName = oname;
+ _ownerId = oid;
+ _type = type;
+ _cReply = Creply;
+ TopicBBSManager.getInstance().addTopic(this);
+
+ if (ct == ConstructorType.CREATE)
+ {
+
+ insertindb();
+ }
+ }
+
+ /**
+ *
+ */
+ public void insertindb()
+ {
+ Connection con = null;
+ try
+ {
+ con = L2DatabaseFactory.getInstance().getConnection();
+ PreparedStatement statement = con.prepareStatement("INSERT INTO topic (topic_id,topic_forum_id,topic_name,topic_date,topic_ownername,topic_ownerid,topic_type,topic_reply) values (?,?,?,?,?,?,?,?)");
+ statement.setInt(1, _id);
+ statement.setInt(2, _forumId);
+ statement.setString(3, _topicName);
+ statement.setLong(4, _date);
+ statement.setString(5, _ownerName);
+ statement.setInt(6, _ownerId);
+ statement.setInt(7, _type);
+ statement.setInt(8, _cReply);
+ statement.execute();
+ statement.close();
+
+ }
+ catch (Exception e)
+ {
+ _log.log(Level.WARNING, "Error while saving new Topic to db " + e.getMessage(), e);
+ }
+ finally
+ {
+ L2DatabaseFactory.close(con);
+ }
+
+ }
+
+ public enum ConstructorType
+ {
+ RESTORE,
+ CREATE
+ }
+
+ /**
+ * @return
+ */
+ public int getID()
+ {
+ return _id;
+ }
+
+ public int getForumID()
+ {
+ return _forumId;
+ }
+
+ /**
+ * @return
+ */
+ public String getName()
+ {
+ return _topicName;
+ }
+
+ public String getOwnerName()
+ {
+ return _ownerName;
+ }
+
+ /**
+ *
+ */
+ public void deleteme(Forum f)
+ {
+ TopicBBSManager.getInstance().delTopic(this);
+ f.rmTopicByID(getID());
+ Connection con = null;
+ try
+ {
+ con = L2DatabaseFactory.getInstance().getConnection();
+ PreparedStatement statement = con.prepareStatement("DELETE FROM topic WHERE topic_id=? AND topic_forum_id=?");
+ statement.setInt(1, getID());
+ statement.setInt(2, f.getID());
+ statement.execute();
+ statement.close();
+ }
+ catch (Exception e)
+ {
+ _log.log(Level.WARNING, "Error while deleting topic: " + e.getMessage(), e);
+ }
+ finally
+ {
+ L2DatabaseFactory.close(con);
+ }
+ }
+
+ /**
+ * @return
+ */
+ public long getDate()
+ {
+ return _date;
+ }
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/communitybbs/CommunityBoard.java b/L2J_Server/java/com/l2jserver/gameserver/communitybbs/CommunityBoard.java
new file mode 100644
index 00000000..e1808f84
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/communitybbs/CommunityBoard.java
@@ -0,0 +1,159 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.communitybbs;
+
+import com.l2jserver.Config;
+import com.l2jserver.gameserver.communitybbs.Manager.ClanBBSManager;
+import com.l2jserver.gameserver.communitybbs.Manager.PostBBSManager;
+import com.l2jserver.gameserver.communitybbs.Manager.RegionBBSManager;
+import com.l2jserver.gameserver.communitybbs.Manager.TopBBSManager;
+import com.l2jserver.gameserver.communitybbs.Manager.TopicBBSManager;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.network.L2GameClient;
+import com.l2jserver.gameserver.network.SystemMessageId;
+import com.l2jserver.gameserver.network.serverpackets.ShowBoard;
+import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
+
+public class CommunityBoard
+{
+ private CommunityBoard()
+ {
+ }
+
+ public static CommunityBoard getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ public void handleCommands(L2GameClient client, String command)
+ {
+ L2PcInstance activeChar = client.getActiveChar();
+ if (activeChar == null)
+ {
+ return;
+ }
+
+ switch (Config.COMMUNITY_TYPE)
+ {
+ default:
+ case 0: // disabled
+ activeChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.CB_OFFLINE));
+ break;
+ case 1: // old
+ RegionBBSManager.getInstance().parsecmd(command, activeChar);
+ break;
+ case 2: // new
+ if (command.startsWith("_bbsclan"))
+ {
+ ClanBBSManager.getInstance().parsecmd(command, activeChar);
+ }
+ else if (command.startsWith("_bbsmemo"))
+ {
+ TopicBBSManager.getInstance().parsecmd(command, activeChar);
+ }
+ else if (command.startsWith("_bbstopics"))
+ {
+ TopicBBSManager.getInstance().parsecmd(command, activeChar);
+ }
+ else if (command.startsWith("_bbsposts"))
+ {
+ PostBBSManager.getInstance().parsecmd(command, activeChar);
+ }
+ else if (command.startsWith("_bbstop"))
+ {
+ TopBBSManager.getInstance().parsecmd(command, activeChar);
+ }
+ else if (command.startsWith("_bbshome"))
+ {
+ TopBBSManager.getInstance().parsecmd(command, activeChar);
+ }
+ else if (command.startsWith("_bbsloc"))
+ {
+ RegionBBSManager.getInstance().parsecmd(command, activeChar);
+ }
+ else
+ {
+ ShowBoard sb = new ShowBoard("
the command: " + command + " is not implemented yet
", "101");
+ activeChar.sendPacket(sb);
+ activeChar.sendPacket(new ShowBoard(null, "102"));
+ activeChar.sendPacket(new ShowBoard(null, "103"));
+ break;
+ }
+ }
+
+ @SuppressWarnings("synthetic-access")
+ private static class SingletonHolder
+ {
+ protected static final CommunityBoard _instance = new CommunityBoard();
+ }
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/communitybbs/Manager/AdminBBSManager.java b/L2J_Server/java/com/l2jserver/gameserver/communitybbs/Manager/AdminBBSManager.java
new file mode 100644
index 00000000..b20fbd36
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/communitybbs/Manager/AdminBBSManager.java
@@ -0,0 +1,77 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.communitybbs.Manager;
+
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.network.serverpackets.ShowBoard;
+
+public class AdminBBSManager extends BaseBBSManager
+{
+ /**
+ * @return
+ */
+ public static AdminBBSManager getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ private AdminBBSManager()
+ {
+ }
+
+ /**
+ * @see com.l2jserver.gameserver.communitybbs.Manager.BaseBBSManager#parsecmd(java.lang.String, com.l2jserver.gameserver.model.actor.instance.L2PcInstance)
+ */
+ @Override
+ public void parsecmd(String command, L2PcInstance activeChar)
+ {
+ if (!activeChar.isGM())
+ {
+ return;
+ }
+ if (command.startsWith("admin_bbs"))
+ {
+ separateAndSend("
the command: " + command + " is not implemented yet
", "101");
+ activeChar.sendPacket(sb);
+ activeChar.sendPacket(new ShowBoard(null, "102"));
+ activeChar.sendPacket(new ShowBoard(null, "103"));
+ }
+
+ }
+
+ /**
+ * @see com.l2jserver.gameserver.communitybbs.Manager.BaseBBSManager#parsewrite(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.l2jserver.gameserver.model.actor.instance.L2PcInstance)
+ */
+ @Override
+ public void parsewrite(String ar1, String ar2, String ar3, String ar4, String ar5, L2PcInstance activeChar)
+ {
+ if (!activeChar.isGM())
+ {
+ return;
+ }
+
+ }
+
+ @SuppressWarnings("synthetic-access")
+ private static class SingletonHolder
+ {
+ protected static final AdminBBSManager _instance = new AdminBBSManager();
+ }
+}
\ No newline at end of file
diff --git a/L2J_Server/java/com/l2jserver/gameserver/communitybbs/Manager/BaseBBSManager.java b/L2J_Server/java/com/l2jserver/gameserver/communitybbs/Manager/BaseBBSManager.java
new file mode 100644
index 00000000..e7495b9a
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/communitybbs/Manager/BaseBBSManager.java
@@ -0,0 +1,105 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.communitybbs.Manager;
+
+import java.util.List;
+
+import javolution.util.FastList;
+
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.network.serverpackets.ShowBoard;
+
+public abstract class BaseBBSManager
+{
+ public abstract void parsecmd(String command, L2PcInstance activeChar);
+
+ public abstract void parsewrite(String ar1, String ar2, String ar3, String ar4, String ar5, L2PcInstance activeChar);
+
+ protected void separateAndSend(String html, L2PcInstance acha)
+ {
+ if (html == null)
+ {
+ return;
+ }
+ if (html.length() < 4090)
+ {
+ acha.sendPacket(new ShowBoard(html, "101"));
+ acha.sendPacket(new ShowBoard(null, "102"));
+ acha.sendPacket(new ShowBoard(null, "103"));
+
+ }
+ else if (html.length() < 8180)
+ {
+ acha.sendPacket(new ShowBoard(html.substring(0, 4090), "101"));
+ acha.sendPacket(new ShowBoard(html.substring(4090, html.length()), "102"));
+ acha.sendPacket(new ShowBoard(null, "103"));
+
+ }
+ else if (html.length() < 12270)
+ {
+ acha.sendPacket(new ShowBoard(html.substring(0, 4090), "101"));
+ acha.sendPacket(new ShowBoard(html.substring(4090, 8180), "102"));
+ acha.sendPacket(new ShowBoard(html.substring(8180, html.length()), "103"));
+
+ }
+ }
+
+ /**
+ * @param html
+ */
+ protected void send1001(String html, L2PcInstance acha)
+ {
+ if (html.length() < 8180)
+ {
+ acha.sendPacket(new ShowBoard(html, "1001"));
+ }
+ }
+
+ /**
+ * @param i
+ */
+ protected void send1002(L2PcInstance acha)
+ {
+ send1002(acha, " ", " ", "0");
+ }
+
+ /**
+ * @param activeChar
+ * @param string
+ * @param string2
+ */
+ protected void send1002(L2PcInstance activeChar, String string, String string2, String string3)
+ {
+ List _arg = new FastList<>();
+ _arg.add("0");
+ _arg.add("0");
+ _arg.add("0");
+ _arg.add("0");
+ _arg.add("0");
+ _arg.add("0");
+ _arg.add(activeChar.getName());
+ _arg.add(Integer.toString(activeChar.getObjectId()));
+ _arg.add(activeChar.getAccountName());
+ _arg.add("9");
+ _arg.add(string2);
+ _arg.add(string2);
+ _arg.add(string);
+ _arg.add(string3);
+ _arg.add(string3);
+ _arg.add("0");
+ _arg.add("0");
+ activeChar.sendPacket(new ShowBoard(_arg));
+ }
+}
diff --git a/L2J_Server/java/com/l2jserver/gameserver/communitybbs/Manager/ClanBBSManager.java b/L2J_Server/java/com/l2jserver/gameserver/communitybbs/Manager/ClanBBSManager.java
new file mode 100644
index 00000000..10b7d6ef
--- /dev/null
+++ b/L2J_Server/java/com/l2jserver/gameserver/communitybbs/Manager/ClanBBSManager.java
@@ -0,0 +1,276 @@
+/*
+ * This program 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.
+ *
+ * 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ */
+package com.l2jserver.gameserver.communitybbs.Manager;
+
+import java.util.StringTokenizer;
+
+import com.l2jserver.gameserver.datatables.ClanTable;
+import com.l2jserver.gameserver.model.L2Clan;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.network.SystemMessageId;
+import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
+import com.l2jserver.util.StringUtil;
+
+public class ClanBBSManager extends BaseBBSManager
+{
+ private ClanBBSManager()
+ {
+ }
+
+ /**
+ * @return
+ */
+ public static ClanBBSManager getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ /**
+ * @param command
+ * @param activeChar
+ */
+ @Override
+ public void parsecmd(String command, L2PcInstance activeChar)
+ {
+ if (command.equals("_bbsclan"))
+ {
+ if ((activeChar.getClan() == null) || (activeChar.getClan().getLevel() < 2))
+ {
+ clanlist(activeChar, 1);
+ }
+ else
+ {
+ clanhome(activeChar);
+ }
+ }
+ else if (command.startsWith("_bbsclan_clanlist"))
+ {
+ if (command.equals("_bbsclan_clanlist"))
+ {
+ clanlist(activeChar, 1);
+ }
+ else if (command.startsWith("_bbsclan_clanlist;"))
+ {
+ StringTokenizer st = new StringTokenizer(command, ";");
+ st.nextToken();
+ int index = Integer.parseInt(st.nextToken());
+ clanlist(activeChar, index);
+ }
+ }
+ else if (command.startsWith("_bbsclan_clanhome"))
+ {
+ if (command.equals("_bbsclan_clanhome"))
+ {
+ clanhome(activeChar);
+ }
+ else if (command.startsWith("_bbsclan_clanhome;"))
+ {
+ StringTokenizer st = new StringTokenizer(command, ";");
+ st.nextToken();
+ int index = Integer.parseInt(st.nextToken());
+ clanhome(activeChar, index);
+ }
+ }
+ else if (command.startsWith("_bbsclan_clannotice_edit;"))
+ {
+ clanNotice(activeChar, activeChar.getClan().getClanId());
+ }
+ else if (command.startsWith("_bbsclan_clannotice_enable"))
+ {
+ activeChar.getClan().setNoticeEnabled(true);
+ clanNotice(activeChar, activeChar.getClan().getClanId());
+ }
+ else if (command.startsWith("_bbsclan_clannotice_disable"))
+ {
+ activeChar.getClan().setNoticeEnabled(false);
+ clanNotice(activeChar, activeChar.getClan().getClanId());
+ }
+ else
+ {
+ separateAndSend("