-
Notifications
You must be signed in to change notification settings - Fork 379
/
008_Game_Player.rb
616 lines (567 loc) · 20.7 KB
/
008_Game_Player.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
#===============================================================================
# ** Game_Player
#-------------------------------------------------------------------------------
# This class handles the player. Its functions include event starting
# determinants and map scrolling. Refer to "$game_player" for the one
# instance of this class.
#===============================================================================
class Game_Player < Game_Character
attr_accessor :charsetData
attr_accessor :encounter_count
SCREEN_CENTER_X = ((Settings::SCREEN_WIDTH / 2) - (Game_Map::TILE_WIDTH / 2)) * Game_Map::X_SUBPIXELS
SCREEN_CENTER_Y = ((Settings::SCREEN_HEIGHT / 2) - (Game_Map::TILE_HEIGHT / 2)) * Game_Map::Y_SUBPIXELS
# Time in seconds for one cycle of bobbing (playing 4 charset frames) while
# surfing or diving.
SURF_BOB_DURATION = 1.5
def initialize(*arg)
super(*arg)
@lastdir = 0
@lastdirframe = 0
end
def map
@map = nil
return $game_map
end
def map_id
return $game_map.map_id
end
def screen_z(height = 0)
ret = super
return ret + 1
end
def has_follower?
return $PokemonGlobal.followers.length > 0
end
def can_map_transfer_with_follower?
return $PokemonGlobal.followers.length == 0
end
def can_ride_vehicle_with_follower?
return $PokemonGlobal.followers.length == 0
end
#-----------------------------------------------------------------------------
def can_run?
return @move_speed > 3 if @move_route_forcing
return false if @bumping
return false if $game_temp.in_menu || $game_temp.in_battle ||
$game_temp.message_window_showing || pbMapInterpreterRunning?
return false if !$player.has_running_shoes && !$PokemonGlobal.diving &&
!$PokemonGlobal.surfing && !$PokemonGlobal.bicycle
return false if jumping?
return false if pbTerrainTag.must_walk
return ($PokemonSystem.runstyle == 1) ^ Input.press?(Input::BACK)
end
def set_movement_type(type)
meta = GameData::PlayerMetadata.get($player&.character_ID || 1)
new_charset = nil
case type
when :fishing
new_charset = pbGetPlayerCharset(meta.fish_charset)
when :surf_fishing
new_charset = pbGetPlayerCharset(meta.surf_fish_charset)
when :diving, :diving_fast, :diving_jumping, :diving_stopped
self.move_speed = 3 if !@move_route_forcing
new_charset = pbGetPlayerCharset(meta.dive_charset)
when :surfing, :surfing_fast, :surfing_jumping, :surfing_stopped
if !@move_route_forcing
self.move_speed = (type == :surfing_jumping) ? 3 : 4
end
new_charset = pbGetPlayerCharset(meta.surf_charset)
when :descending_waterfall, :ascending_waterfall
self.move_speed = 2 if !@move_route_forcing
new_charset = pbGetPlayerCharset(meta.surf_charset)
when :cycling, :cycling_fast, :cycling_jumping, :cycling_stopped
if !@move_route_forcing
self.move_speed = (type == :cycling_jumping) ? 3 : 5
end
new_charset = pbGetPlayerCharset(meta.cycle_charset)
when :running
self.move_speed = 4 if !@move_route_forcing
new_charset = pbGetPlayerCharset(meta.run_charset)
when :ice_sliding
self.move_speed = 4 if !@move_route_forcing
new_charset = pbGetPlayerCharset(meta.walk_charset)
else # :walking, :jumping, :walking_stopped
self.move_speed = 3 if !@move_route_forcing
new_charset = pbGetPlayerCharset(meta.walk_charset)
end
self.move_speed = 3 if @bumping
@character_name = new_charset if new_charset
end
# Called when the player's character or outfit changes. Assumes the player
# isn't moving.
def refresh_charset
meta = GameData::PlayerMetadata.get($player&.character_ID || 1)
new_charset = nil
if $PokemonGlobal&.diving
new_charset = pbGetPlayerCharset(meta.dive_charset)
elsif $PokemonGlobal&.surfing
new_charset = pbGetPlayerCharset(meta.surf_charset)
elsif $PokemonGlobal&.bicycle
new_charset = pbGetPlayerCharset(meta.cycle_charset)
else
new_charset = pbGetPlayerCharset(meta.walk_charset)
end
@character_name = new_charset if new_charset
end
#-----------------------------------------------------------------------------
def bump_into_object
pbSEPlay("Player bump") if !@move_route_forcing
$stats.bump_count += 1
@move_initial_x = @x
@move_initial_y = @y
@move_timer = 0.0
@bumping = true
end
def add_move_distance_to_stats(distance = 1)
if $PokemonGlobal&.diving || $PokemonGlobal&.surfing
$stats.distance_surfed += distance
elsif $PokemonGlobal&.bicycle
$stats.distance_cycled += distance
else
$stats.distance_walked += distance
end
$stats.distance_slid_on_ice += distance if $PokemonGlobal.ice_sliding
end
def move_generic(dir, turn_enabled = true)
turn_generic(dir, true) if turn_enabled
if !$game_temp.encounter_triggered
if can_move_in_direction?(dir)
x_offset = (dir == 4) ? -1 : (dir == 6) ? 1 : 0
y_offset = (dir == 8) ? -1 : (dir == 2) ? 1 : 0
# Jump over ledges
if pbFacingTerrainTag.ledge
if jumpForward(2)
pbSEPlay("Player jump")
increase_steps
end
return
elsif pbFacingTerrainTag.waterfall_crest && dir == 2
$PokemonGlobal.descending_waterfall = true
$game_player.through = true
$stats.waterfalls_descended += 1
end
# Jumping out of surfing back onto land
return if pbEndSurf(x_offset, y_offset)
# General movement
turn_generic(dir, true)
if !$game_temp.encounter_triggered
@move_initial_x = @x
@move_initial_y = @y
@x += x_offset
@y += y_offset
@move_timer = 0.0
add_move_distance_to_stats(x_offset.abs + y_offset.abs)
increase_steps
end
elsif !check_event_trigger_touch(dir)
bump_into_object
end
end
$game_temp.encounter_triggered = false
end
def turn_generic(dir, keep_enc_indicator = false)
old_direction = @direction
super(dir)
if @direction != old_direction && !@move_route_forcing && !pbMapInterpreterRunning?
EventHandlers.trigger(:on_player_change_direction)
$game_temp.encounter_triggered = false if !keep_enc_indicator
end
end
def jump(x_plus, y_plus)
old_x = @x
old_y = @y
super
add_move_distance_to_stats(x_plus.abs + y_plus.abs) if @x != old_x || @y != old_y
end
#-----------------------------------------------------------------------------
def pbTerrainTag(countBridge = false)
return $map_factory.getTerrainTagFromCoords(self.map.map_id, @x, @y, countBridge) if $map_factory
return $game_map.terrain_tag(@x, @y, countBridge)
end
def pbFacingEvent(ignoreInterpreter = false)
return nil if $game_system.map_interpreter.running? && !ignoreInterpreter
# Check the tile in front of the player for events
new_x = @x + (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
new_y = @y + (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
return nil if !$game_map.valid?(new_x, new_y)
$game_map.events.each_value do |event|
next if !event.at_coordinate?(new_x, new_y)
next if event.jumping? || event.over_trigger?
return event
end
# If the tile in front is a counter, check one tile beyond that for events
if $game_map.counter?(new_x, new_y)
new_x += (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
new_y += (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
$game_map.events.each_value do |event|
next if !event.at_coordinate?(new_x, new_y)
next if event.jumping? || event.over_trigger?
return event
end
end
return nil
end
def pbFacingTerrainTag(dir = nil)
dir = self.direction if !dir
return $map_factory.getFacingTerrainTag(dir, self) if $map_factory
facing = pbFacingTile(dir, self)
return $game_map.terrain_tag(facing[1], facing[2])
end
# Passable Determinants
# x : x-coordinate
# y : y-coordinate
# d : direction (0, 2, 4, 6, 8)
# * 0 = Determines if all directions are impassable (for jumping)
def passable?(x, y, d, strict = false)
# Get new coordinates
new_x = x + (d == 6 ? 1 : d == 4 ? -1 : 0)
new_y = y + (d == 2 ? 1 : d == 8 ? -1 : 0)
# If coordinates are outside of map
return false if !$game_map.validLax?(new_x, new_y)
if !$game_map.valid?(new_x, new_y)
return false if !$map_factory
return $map_factory.isPassableFromEdge?(new_x, new_y)
end
# If debug mode is ON and Ctrl key was pressed
return true if $DEBUG && Input.press?(Input::CTRL)
return super
end
# Set Map Display Position to Center of Screen
def center(x, y)
self.map.display_x = (x * Game_Map::REAL_RES_X) - SCREEN_CENTER_X
self.map.display_y = (y * Game_Map::REAL_RES_Y) - SCREEN_CENTER_Y
end
# Move to Designated Position
# x : x-coordinate
# y : y-coordinate
def moveto(x, y)
super
center(x, y)
make_encounter_count
end
# Make Encounter Count
def make_encounter_count
# Image of two dice rolling
if $game_map.map_id != 0
n = $game_map.encounter_step
@encounter_count = rand(n) + rand(n) + 1
end
end
def refresh
@opacity = 255
@blend_type = 0
end
#-----------------------------------------------------------------------------
def pbTriggeredTrainerEvents(triggers, checkIfRunning = true, trainer_only = false)
result = []
# If event is running
return result if checkIfRunning && $game_system.map_interpreter.running?
# All event loops
$game_map.events.each_value do |event|
next if !triggers.include?(event.trigger)
next if !event.name[/trainer\((\d+)\)/i] && (trainer_only || !event.name[/sight\((\d+)\)/i])
distance = $~[1].to_i
next if !pbEventCanReachPlayer?(event, self, distance)
next if event.jumping? || event.over_trigger?
result.push(event)
end
return result
end
def pbTriggeredCounterEvents(triggers, checkIfRunning = true)
result = []
# If event is running
return result if checkIfRunning && $game_system.map_interpreter.running?
# All event loops
$game_map.events.each_value do |event|
next if !triggers.include?(event.trigger)
next if !event.name[/counter\((\d+)\)/i]
distance = $~[1].to_i
next if !pbEventFacesPlayer?(event, self, distance)
next if event.jumping? || event.over_trigger?
result.push(event)
end
return result
end
def check_event_trigger_after_turning; end
def pbCheckEventTriggerFromDistance(triggers)
events = pbTriggeredTrainerEvents(triggers)
events.concat(pbTriggeredCounterEvents(triggers))
return false if events.length == 0
ret = false
events.each do |event|
event.start
ret = true if event.starting
end
return ret
end
# Trigger event(s) at the same coordinates as self with the appropriate
# trigger(s) that can be triggered
def check_event_trigger_here(triggers)
result = false
# If event is running
return result if $game_system.map_interpreter.running?
# All event loops
$game_map.events.each_value do |event|
# If event coordinates and triggers are consistent
next if !event.at_coordinate?(@x, @y)
next if !triggers.include?(event.trigger)
# If starting determinant is same position event (other than jumping)
next if event.jumping? || !event.over_trigger?
event.start
result = true if event.starting
end
return result
end
# Front Event Starting Determinant
def check_event_trigger_there(triggers)
result = false
# If event is running
return result if $game_system.map_interpreter.running?
# Calculate front event coordinates
new_x = @x + (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
new_y = @y + (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
return false if !$game_map.valid?(new_x, new_y)
# All event loops
$game_map.events.each_value do |event|
next if !triggers.include?(event.trigger)
# If event coordinates and triggers are consistent
next if !event.at_coordinate?(new_x, new_y)
# If starting determinant is front event (other than jumping)
next if event.jumping? || event.over_trigger?
event.start
result = true if event.starting
end
# If fitting event is not found
if result == false && $game_map.counter?(new_x, new_y)
# Calculate coordinates of 1 tile further away
new_x += (@direction == 6 ? 1 : @direction == 4 ? -1 : 0)
new_y += (@direction == 2 ? 1 : @direction == 8 ? -1 : 0)
return false if !$game_map.valid?(new_x, new_y)
# All event loops
$game_map.events.each_value do |event|
next if !triggers.include?(event.trigger)
# If event coordinates and triggers are consistent
next if !event.at_coordinate?(new_x, new_y)
# If starting determinant is front event (other than jumping)
next if event.jumping? || event.over_trigger?
event.start
result = true if event.starting
end
end
return result
end
# Touch Event Starting Determinant
def check_event_trigger_touch(dir)
result = false
return result if $game_system.map_interpreter.running?
# All event loops
x_offset = (dir == 4) ? -1 : (dir == 6) ? 1 : 0
y_offset = (dir == 8) ? -1 : (dir == 2) ? 1 : 0
$game_map.events.each_value do |event|
next if ![1, 2].include?(event.trigger) # Player touch, event touch
# If event coordinates and triggers are consistent
next if !event.at_coordinate?(@x + x_offset, @y + y_offset)
if event.name[/(?:sight|trainer)\((\d+)\)/i]
distance = $~[1].to_i
next if !pbEventCanReachPlayer?(event, self, distance)
elsif event.name[/counter\((\d+)\)/i]
distance = $~[1].to_i
next if !pbEventFacesPlayer?(event, self, distance)
end
# If starting determinant is front event (other than jumping)
next if event.jumping? || event.over_trigger?
event.start
result = true if event.starting
end
return result
end
#-----------------------------------------------------------------------------
def update
last_real_x = @real_x
last_real_y = @real_y
@last_terrain_tag = pbTerrainTag
super
update_stop if $game_temp.in_menu && @stopped_last_frame
update_screen_position(last_real_x, last_real_y)
# Update dependent events
if (!@moved_last_frame || @stopped_last_frame) && (moving? || jumping?) && !@bumping
$game_temp.followers.move_followers
end
$game_temp.followers.update
update_event_triggering
end
def update_command_new
dir = Input.dir4
if $PokemonGlobal.forced_movement?
move_forward
elsif !pbMapInterpreterRunning? && !$game_temp.message_window_showing &&
!$game_temp.in_mini_update && !$game_temp.in_menu
# Move player in the direction the directional button is being pressed
if @moved_last_frame ||
(dir > 0 && dir == @lastdir && System.uptime - @lastdirframe >= 0.075)
case dir
when 2 then move_down
when 4 then move_left
when 6 then move_right
when 8 then move_up
end
elsif dir != @lastdir
case dir
when 2 then turn_down
when 4 then turn_left
when 6 then turn_right
when 8 then turn_up
end
end
# Record last direction input
@lastdirframe = System.uptime if dir != @lastdir
@lastdir = dir
end
end
def update_move
if !@moved_last_frame || @stopped_last_frame # Started a new step
if $PokemonGlobal.ice_sliding || @last_terrain_tag.ice
set_movement_type(:ice_sliding)
elsif $PokemonGlobal.descending_waterfall
set_movement_type(:descending_waterfall)
elsif $PokemonGlobal.ascending_waterfall
set_movement_type(:ascending_waterfall)
else
faster = can_run?
if $PokemonGlobal&.diving
set_movement_type((faster) ? :diving_fast : :diving)
elsif $PokemonGlobal&.surfing
set_movement_type((faster) ? :surfing_fast : :surfing)
elsif $PokemonGlobal&.bicycle
set_movement_type((faster) ? :cycling_fast : :cycling)
else
set_movement_type((faster) ? :running : :walking)
end
end
if jumping?
if $PokemonGlobal&.diving
set_movement_type(:diving_jumping)
elsif $PokemonGlobal&.surfing
set_movement_type(:surfing_jumping)
elsif $PokemonGlobal&.bicycle
set_movement_type(:cycling_jumping)
else
set_movement_type(:jumping) # Walking speed/charset while jumping
end
end
end
was_jumping = jumping?
super
if was_jumping && !jumping? && !@transparent && (@tile_id > 0 || @character_name != "")
if !$PokemonGlobal.surfing || $game_temp.ending_surf
spriteset = $scene.spriteset(map_id)
spriteset&.addUserAnimation(Settings::DUST_ANIMATION_ID, self.x, self.y, true, 1)
end
end
end
def update_stop
if @stopped_last_frame
if $PokemonGlobal&.diving
set_movement_type(:diving_stopped)
elsif $PokemonGlobal&.surfing
set_movement_type(:surfing_stopped)
elsif $PokemonGlobal&.bicycle
set_movement_type(:cycling_stopped)
else
set_movement_type(:walking_stopped)
end
end
super
end
def update_pattern
if $PokemonGlobal&.surfing || $PokemonGlobal&.diving
bob_pattern = (4 * System.uptime / SURF_BOB_DURATION).to_i % 4
@pattern = bob_pattern if !@lock_pattern
@pattern_surf = bob_pattern
@bob_height = (bob_pattern >= 2) ? 2 : 0
@anime_count = 0
else
@bob_height = 0
super
end
end
# Track the player on-screen as they move.
def update_screen_position(last_real_x, last_real_y)
return if self.map.scrolling? || !(@moved_last_frame || @moved_this_frame)
if (@real_x < last_real_x && @real_x < $game_map.display_x + SCREEN_CENTER_X) ||
(@real_x > last_real_x && @real_x > $game_map.display_x + SCREEN_CENTER_X)
self.map.display_x += @real_x - last_real_x
end
if (@real_y < last_real_y && @real_y < $game_map.display_y + SCREEN_CENTER_Y) ||
(@real_y > last_real_y && @real_y > $game_map.display_y + SCREEN_CENTER_Y)
self.map.display_y += @real_y - last_real_y
end
end
def update_event_triggering
return if moving? || jumping? || $PokemonGlobal.forced_movement?
# Try triggering events upon walking into them/in front of them
if @moved_this_frame
$game_temp.followers.turn_followers
result = pbCheckEventTriggerFromDistance([2])
# Event determinant is via touch of same position event
result |= check_event_trigger_here([1, 2])
# No events triggered, try other event triggers upon finishing a step
pbOnStepTaken(result)
end
end
end
#===============================================================================
#
#===============================================================================
def pbGetPlayerCharset(charset, trainer = nil, force = false)
trainer = $player if !trainer
outfit = (trainer) ? trainer.outfit : 0
return nil if !force && $game_player&.charsetData &&
$game_player.charsetData[0] == trainer.character_ID &&
$game_player.charsetData[1] == charset &&
$game_player.charsetData[2] == outfit
$game_player.charsetData = [trainer.character_ID, charset, outfit] if $game_player
ret = charset
if pbResolveBitmap("Graphics/Characters/" + ret + "_" + outfit.to_s)
ret = ret + "_" + outfit.to_s
end
return ret
end
def pbUpdateVehicle
if $PokemonGlobal&.diving
$game_player.set_movement_type(:diving_stopped)
elsif $PokemonGlobal&.surfing
$game_player.set_movement_type(:surfing_stopped)
elsif $PokemonGlobal&.bicycle
$game_player.set_movement_type(:cycling_stopped)
else
$game_player.set_movement_type(:walking_stopped)
end
end
def pbCancelVehicles(destination = nil, cancel_swimming = true)
$PokemonGlobal.surfing = false if cancel_swimming
$PokemonGlobal.diving = false if cancel_swimming
$PokemonGlobal.bicycle = false if !destination || !pbCanUseBike?(destination)
pbUpdateVehicle
end
def pbCanUseBike?(map_id)
map_metadata = GameData::MapMetadata.try_get(map_id)
return false if !map_metadata
return map_metadata.always_bicycle || map_metadata.can_bicycle || map_metadata.outdoor_map
end
def pbMountBike
return if $PokemonGlobal.bicycle
$PokemonGlobal.bicycle = true
$stats.cycle_count += 1
pbUpdateVehicle
bike_bgm = GameData::Metadata.get.bicycle_BGM
pbCueBGM(bike_bgm, 0.4) if bike_bgm
pbSEPlay("Bicycle")
pbPokeRadarCancel
end
def pbDismountBike
return if !$PokemonGlobal.bicycle
$PokemonGlobal.bicycle = false
pbUpdateVehicle
$game_map.autoplayAsCue
end