@rpgjs/server 5.0.0-alpha.21 → 5.0.0-alpha.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -172,6 +172,11 @@ export class RpgPlayer extends BasicPlayerMixins(RpgCommonPlayer) {
172
172
  return inject<Hooks>(this.context as any, ModulesToken);
173
173
  }
174
174
 
175
+ // compatibility with v4
176
+ get server() {
177
+ return this.map
178
+ }
179
+
175
180
  applyFrames() {
176
181
  this._frames.set(this.frames)
177
182
  this.frames = []
@@ -862,6 +867,218 @@ export class RpgPlayer extends BasicPlayerMixins(RpgCommonPlayer) {
862
867
  this.emit("stopSound", data);
863
868
  }
864
869
 
870
+ /**
871
+ * Stop all currently playing sounds for this player
872
+ *
873
+ * This method stops all sounds that are currently playing for the player.
874
+ * Useful when changing maps to prevent sound overlap.
875
+ *
876
+ * @example
877
+ * ```ts
878
+ * // Stop all sounds before changing map
879
+ * player.stopAllSounds();
880
+ * await player.changeMap("new-map");
881
+ * ```
882
+ */
883
+ stopAllSounds(): void {
884
+ const map = this.getCurrentMap();
885
+ if (!map) return;
886
+
887
+ // Send stop all command only to this player
888
+ this.emit("stopAllSounds", {});
889
+ }
890
+
891
+ /**
892
+ * Make the camera follow another player or event
893
+ *
894
+ * This method sends an instruction to the client to fix the viewport on another sprite.
895
+ * The camera will follow the specified player or event, with optional smooth animation.
896
+ *
897
+ * ## Design
898
+ *
899
+ * The camera follow instruction is sent only to this player's client connection.
900
+ * This allows each player to have their own camera target, useful for cutscenes,
901
+ * following NPCs, or focusing on specific events.
902
+ *
903
+ * @param otherPlayer - The player or event that the camera should follow
904
+ * @param options - Camera follow options
905
+ * @param options.smoothMove - Enable smooth animation. Can be a boolean (default: true) or an object with animation parameters
906
+ * @param options.smoothMove.time - Time duration for the animation in milliseconds (optional)
907
+ * @param options.smoothMove.ease - Easing function name. Visit https://easings.net for available functions (optional)
908
+ *
909
+ * @example
910
+ * ```ts
911
+ * // Follow another player with default smooth animation
912
+ * player.cameraFollow(otherPlayer, { smoothMove: true });
913
+ *
914
+ * // Follow an event with custom smooth animation
915
+ * player.cameraFollow(npcEvent, {
916
+ * smoothMove: {
917
+ * time: 1000,
918
+ * ease: "easeInOutQuad"
919
+ * }
920
+ * });
921
+ *
922
+ * // Follow without animation (instant)
923
+ * player.cameraFollow(targetPlayer, { smoothMove: false });
924
+ * ```
925
+ */
926
+ cameraFollow(
927
+ otherPlayer: RpgPlayer | RpgEvent,
928
+ options?: {
929
+ smoothMove?: boolean | { time?: number; ease?: string };
930
+ }
931
+ ): void {
932
+ const map = this.getCurrentMap();
933
+ if (!map) return;
934
+
935
+ const data: any = {
936
+ targetId: otherPlayer.id,
937
+ };
938
+
939
+ // Handle smoothMove option
940
+ if (options?.smoothMove !== undefined) {
941
+ if (typeof options.smoothMove === "boolean") {
942
+ data.smoothMove = options.smoothMove;
943
+ } else {
944
+ // smoothMove is an object
945
+ data.smoothMove = {
946
+ enabled: true,
947
+ ...options.smoothMove,
948
+ };
949
+ }
950
+ } else {
951
+ // Default to true if not specified
952
+ data.smoothMove = true;
953
+ }
954
+
955
+ // Send camera follow instruction only to this player
956
+ this.emit("cameraFollow", data);
957
+ }
958
+
959
+
960
+ /**
961
+ * Trigger a flash animation on this player
962
+ *
963
+ * This method sends a flash animation event to the client, creating a visual
964
+ * feedback effect on the player's sprite. The flash can be configured with
965
+ * various options including type (alpha, tint, or both), duration, cycles, and color.
966
+ *
967
+ * ## Design
968
+ *
969
+ * The flash is sent as a broadcast event to all clients viewing this player.
970
+ * This is useful for visual feedback when the player takes damage, receives
971
+ * a buff, or when an important event occurs.
972
+ *
973
+ * @param options - Flash configuration options
974
+ * @param options.type - Type of flash effect: 'alpha' (opacity), 'tint' (color), or 'both' (default: 'alpha')
975
+ * @param options.duration - Duration of the flash animation in milliseconds (default: 300)
976
+ * @param options.cycles - Number of flash cycles (flash on/off) (default: 1)
977
+ * @param options.alpha - Alpha value when flashing, from 0 to 1 (default: 0.3)
978
+ * @param options.tint - Tint color when flashing as hex value or color name (default: 0xffffff - white)
979
+ *
980
+ * @example
981
+ * ```ts
982
+ * // Simple flash with default settings (alpha flash)
983
+ * player.flash();
984
+ *
985
+ * // Flash with red tint when taking damage
986
+ * player.flash({ type: 'tint', tint: 0xff0000 });
987
+ *
988
+ * // Flash with both alpha and tint for dramatic effect
989
+ * player.flash({
990
+ * type: 'both',
991
+ * alpha: 0.5,
992
+ * tint: 0xff0000,
993
+ * duration: 200,
994
+ * cycles: 2
995
+ * });
996
+ *
997
+ * // Quick damage flash
998
+ * player.flash({
999
+ * type: 'tint',
1000
+ * tint: 'red',
1001
+ * duration: 150,
1002
+ * cycles: 1
1003
+ * });
1004
+ * ```
1005
+ */
1006
+ flash(options?: {
1007
+ type?: 'alpha' | 'tint' | 'both';
1008
+ duration?: number;
1009
+ cycles?: number;
1010
+ alpha?: number;
1011
+ tint?: number | string;
1012
+ }): void {
1013
+ const map = this.getCurrentMap();
1014
+ if (!map) return;
1015
+
1016
+ const flashOptions = {
1017
+ type: options?.type || 'alpha',
1018
+ duration: options?.duration ?? 300,
1019
+ cycles: options?.cycles ?? 1,
1020
+ alpha: options?.alpha ?? 0.3,
1021
+ tint: options?.tint ?? 0xffffff,
1022
+ };
1023
+
1024
+ map.$broadcast({
1025
+ type: "flash",
1026
+ value: {
1027
+ object: this.id,
1028
+ ...flashOptions,
1029
+ },
1030
+ });
1031
+ }
1032
+
1033
+ /**
1034
+ * Set the hitbox of the player for collision detection
1035
+ *
1036
+ * This method defines the hitbox used for collision detection in the physics engine.
1037
+ * The hitbox can be smaller or larger than the visual representation of the player,
1038
+ * allowing for precise collision detection.
1039
+ *
1040
+ * ## Design
1041
+ *
1042
+ * The hitbox is used by the physics engine to detect collisions with other entities,
1043
+ * static obstacles, and shapes. Changing the hitbox will immediately update the
1044
+ * collision detection without affecting the visual appearance of the player.
1045
+ *
1046
+ * @param width - Width of the hitbox in pixels
1047
+ * @param height - Height of the hitbox in pixels
1048
+ *
1049
+ * @example
1050
+ * ```ts
1051
+ * // Set a 20x20 hitbox for precise collision detection
1052
+ * player.setHitbox(20, 20);
1053
+ *
1054
+ * // Set a larger hitbox for easier collision detection
1055
+ * player.setHitbox(40, 40);
1056
+ * ```
1057
+ */
1058
+ setHitbox(width: number, height: number): void {
1059
+ // Validate inputs
1060
+ if (typeof width !== 'number' || width <= 0) {
1061
+ throw new Error('setHitbox: width must be a positive number');
1062
+ }
1063
+ if (typeof height !== 'number' || height <= 0) {
1064
+ throw new Error('setHitbox: height must be a positive number');
1065
+ }
1066
+
1067
+ // Update hitbox signal
1068
+ this.hitbox.set({
1069
+ w: width,
1070
+ h: height,
1071
+ });
1072
+
1073
+ // Update physics entity if map exists
1074
+ const map = this.getCurrentMap();
1075
+ if (map && map.physic) {
1076
+ const topLeftX = this.x();
1077
+ const topLeftY = this.y();
1078
+ map.updateHitbox(this.id, topLeftX, topLeftY, width, height);
1079
+ }
1080
+ }
1081
+
865
1082
  /**
866
1083
  * Set the sync schema for the map
867
1084
  * @param schema - The schema to set
@@ -61,50 +61,11 @@ export function WithSkillManager<TBase extends PlayerCtor>(Base: TBase) {
61
61
  });
62
62
  }
63
63
 
64
- /**
65
- * Retrieves a learned skill. Returns null, if not found
66
- * ```ts
67
- * import Fire from 'your-database/skills/fire'
68
- *
69
- * player.getSkill(Fire)
70
- * ```
71
- *
72
- * @title Get Skill
73
- * @method player.getSkill(skillClass)
74
- * @param {SkillClass | string} skillClass or data id
75
- * @returns {instance of SkillClass | null}
76
- * @memberof SkillManager
77
- */
78
64
  getSkill(skillClass: any | string) {
79
65
  const index = this._getSkillIndex(skillClass);
80
66
  return this.skills()[index] ?? null;
81
67
  }
82
68
 
83
- /**
84
- * Learn a skill. Attributes the coefficient 1 to the parameter INT (intelligence) if cd is not present on the class.
85
- *
86
- * `onLearn()` method is called on the SkillClass
87
- *
88
- * ```ts
89
- * import Fire from 'your-database/skills/fire'
90
- *
91
- * player.learnSkill(Fire)
92
- * ```
93
- *
94
- * @title Learn Skill
95
- * @method player.learnSkill(skillClass)
96
- * @param {SkillClass | string} skillId or data id
97
- * @throws {SkillLog} alreadyLearned
98
- * If the player already knows the skill
99
- * ```
100
- {
101
- id: SKILL_ALREADY_LEARNED,
102
- msg: '...'
103
- }
104
- ```
105
- * @returns {instance of SkillClass}
106
- * @memberof SkillManager
107
- */
108
69
  learnSkill(skillId: any | string) {
109
70
  if (this.getSkill(skillId)) {
110
71
  throw SkillLog.alreadyLearned(skillId);
@@ -115,36 +76,6 @@ export function WithSkillManager<TBase extends PlayerCtor>(Base: TBase) {
115
76
  return instance;
116
77
  }
117
78
 
118
- /**
119
- * Forget a skill
120
- *
121
- * `onForget()` method is called on the SkillClass
122
- *
123
- * ```ts
124
- * import Fire from 'your-database/skills/fire'
125
- *
126
- * try {
127
- * player.forgetSkill(Fire)
128
- * }
129
- * catch (err) {
130
- * console.log(err)
131
- * }
132
- * ```
133
- *
134
- * @title Forget Skill
135
- * @method player.learnSkill(skillClass)
136
- * @param {SkillClass | string} skillId or data id
137
- * @throws {SkillLog} notLearned
138
- * If trying to forget a skill not learned
139
- * ```
140
- * {
141
- * id: SKILL_NOT_LEARNED,
142
- * msg: '...'
143
- * }
144
- * ```
145
- * @returns {instance of SkillClass}
146
- * @memberof SkillManager
147
- */
148
79
  forgetSkill(skillId: any | string) {
149
80
  if (isString(skillId)) skillId = (this as any).databaseById(skillId);
150
81
  const index = this._getSkillIndex(skillId);
@@ -157,81 +88,6 @@ export function WithSkillManager<TBase extends PlayerCtor>(Base: TBase) {
157
88
  return instance;
158
89
  }
159
90
 
160
- /**
161
- * Using a skill
162
- *
163
- * `onUse()` method is called on the SkillClass
164
- *
165
- * If other players are indicated then damage will be done to these other players. The method `applyDamage()` will be executed
166
- *
167
- * ```ts
168
- * import Fire from 'your-database/skills/fire'
169
- *
170
- * try {
171
- * player.useSkill(Fire)
172
- * }
173
- * catch (err) {
174
- * console.log(err)
175
- * }
176
- * ```
177
- *
178
- * or
179
- *
180
- *
181
- * * ```ts
182
- * import Fire from 'your-database/skills/fire'
183
- *
184
- * try {
185
- * player.useSkill(Fire, otherPlayer)
186
- * }
187
- * catch (err) {
188
- * console.log(err)
189
- * }
190
- * ```
191
- *
192
- * @title Use Skill
193
- * @method player.useSkill(skillClass,otherPlayer)
194
- * @param {SkillClass | string} skillId or data id
195
- * @param {Array<RpgPlayer> | RpgPlayer} [otherPlayer]
196
- * @throws {SkillLog} restriction
197
- * If the player has the `Effect.CAN_NOT_SKILL` effect
198
- * ```
199
- * {
200
- * id: RESTRICTION_SKILL,
201
- * msg: '...'
202
- * }
203
- * ```
204
- * @throws {SkillLog} notLearned
205
- * If the player tries to use an unlearned skill
206
- * ```
207
- * {
208
- * id: SKILL_NOT_LEARNED,
209
- * msg: '...'
210
- * }
211
- * ```
212
- * @throws {SkillLog} notEnoughSp
213
- * If the player does not have enough SP to use the skill
214
- * ```
215
- * {
216
- * id: NOT_ENOUGH_SP,
217
- * msg: '...'
218
- * }
219
- * ```
220
- * @throws {SkillLog} chanceToUseFailed
221
- * If the chance to use the skill has failed (defined with the `hitRate` property)
222
- * ```
223
- * {
224
- * id: USE_CHANCE_SKILL_FAILED,
225
- * msg: '...'
226
- * }
227
- * ```
228
- *
229
- * `onUseFailed()` method is called on the SkillClass
230
- *
231
- * @returns {instance of SkillClass}
232
- * @memberof SkillManager
233
- * @todo
234
- */
235
91
  useSkill(skillId: any | string, otherPlayer?: RpgPlayer | RpgPlayer[]) {
236
92
  const skill = this.getSkill(skillId);
237
93
  if ((this as any).hasEffect(Effect.CAN_NOT_SKILL)) {
@@ -266,7 +122,48 @@ export function WithSkillManager<TBase extends PlayerCtor>(Base: TBase) {
266
122
  }
267
123
 
268
124
  /**
269
- * Type helper to extract the interface from the WithSkillManager mixin
270
- * This provides the type without duplicating method signatures
125
+ * Interface for Skill Manager functionality
126
+ *
127
+ * Provides skill management capabilities including learning, forgetting, and using skills.
128
+ * This interface defines the public API of the SkillManager mixin.
271
129
  */
272
- export type ISkillManager = InstanceType<ReturnType<typeof WithSkillManager>>;
130
+ export interface ISkillManager {
131
+ /**
132
+ * Retrieves a learned skill. Returns null if not found
133
+ *
134
+ * @param skillClass - Skill class or data id
135
+ * @returns Instance of SkillClass or null
136
+ */
137
+ getSkill(skillClass: any | string): any | null;
138
+
139
+ /**
140
+ * Learn a skill
141
+ *
142
+ * @param skillId - Skill class or data id
143
+ * @returns Instance of SkillClass
144
+ * @throws SkillLog.alreadyLearned if the player already knows the skill
145
+ */
146
+ learnSkill(skillId: any | string): any;
147
+
148
+ /**
149
+ * Forget a skill
150
+ *
151
+ * @param skillId - Skill class or data id
152
+ * @returns Instance of SkillClass
153
+ * @throws SkillLog.notLearned if trying to forget a skill not learned
154
+ */
155
+ forgetSkill(skillId: any | string): any;
156
+
157
+ /**
158
+ * Using a skill
159
+ *
160
+ * @param skillId - Skill class or data id
161
+ * @param otherPlayer - Optional target player(s) to apply skill to
162
+ * @returns Instance of SkillClass
163
+ * @throws SkillLog.restriction if player has Effect.CAN_NOT_SKILL
164
+ * @throws SkillLog.notLearned if player tries to use an unlearned skill
165
+ * @throws SkillLog.notEnoughSp if player does not have enough SP
166
+ * @throws SkillLog.chanceToUseFailed if the chance to use the skill has failed
167
+ */
168
+ useSkill(skillId: any | string, otherPlayer?: RpgPlayer | RpgPlayer[]): any;
169
+ }