· 6 years ago · Apr 24, 2019, 04:48 PM
1__END__
2
3# CREDITS:
4# - Mr. "Jteo" Gela
5# - Toxicroak
6# - angrybanana5000
7# - bobandbill
8# - Shauna
9# - Yusshin
10# - Team Rocket's Raichu
11# - April
12# - Team Fail
13# - IceCatraz
14# - kittikatt
15# - rizyq
16# - Sasuke
17# - steffyace
18# - Panfisha
19# - Glow Worm's Not Glowing
20# - chamo-chan
21# - billios
22# - little monster
23# - mastermack0
24
25# TODO:
26# #DONE# - Actual animation popups themselves when interacting
27# #DONE# - Support for Female overworld sprites
28# - Status condition tones? If that's an actual official thing?
29# #DONE# - Have the follower load at the correct angle/side upon loading the game
30# #DONE# - Seamless map transitions
31# #DONE# - Follower coming out upon map transition if it was retracted
32# - Crash upon toggling at map edge
33# - Move Routes
34# - When toggling follower on map edge it can cause instant/pop transition
35
36module Follower
37 # Whether or not you want the follower overworld sprite to be animated or not
38 # when the player is not moving.
39 IdleAnimation = true
40
41 # Has to be inside Graphics/Characters. This folder will contain all the pokemon
42 # overworld sprites.
43 PokemonFollowingSpritePath = "Graphics/Characters/Following Pokemon/Overworlds"
44end
45
46class Game_Event
47 attr_accessor :event
48 attr_accessor :page
49end
50
51class DependentEvents
52 attr_accessor :realEvents
53
54 # Overwrites [addEvent] to support a number of additional options:
55 # - Walk Animation
56 # - Step Animation
57 # - Direction Fix
58 # - Through
59 # - Always On Top
60 def addEvent(event, eventName = nil, commonEvent = nil)
61 return unless event
62 events = $PokemonGlobal.dependentEvents
63 for i in 0...events.length
64 if events[i] && events[i][0] == $game_map.map_id && events[i][1] == event.id
65 return
66 end
67 end
68 eventData = [
69 $game_map.map_id, event.id, $game_map.map_id,
70 event.x, event.y, event.direction,
71 event.character_name.clone,
72 event.character_hue, eventName, commonEvent,
73 event.move_route, event.walk_anime, event.step_anime,
74 event.direction_fix, event.through, event.always_on_top,
75 event.special_list, event.special_graphic
76 ]
77 newEvent = createEvent(eventData)
78 events.push(eventData)
79 @realEvents.push(newEvent)
80 @lastUpdate += 1
81 event.erase if event.respond_to?(:erase)
82 return @realEvents.index(newEvent)
83 end
84
85 # Overwrites [createEvent] to support a number of additional options:
86 # - Walk Animation
87 # - Step Animation
88 # - Direction Fix
89 # - Through
90 # - Always On Top
91 def createEvent(eventData)
92 rpgEvent = RPG::Event.new(eventData[3],eventData[4])
93 rpgEvent.id = eventData[1]
94 rpgEvent.name = eventData[8]
95 if eventData[9]
96 # Must setup common event list here and now
97 commonEvent = Game_CommonEvent.new(eventData[9])
98 rpgEvent.pages[0].list = commonEvent.list
99 elsif eventData[16]
100 rpgEvent.pages[0].list = eventData[16]
101 end
102 rpgEvent.pages[0].move_route = eventData[10]
103 rpgEvent.pages[0].walk_anime = eventData[11]
104 rpgEvent.pages[0].step_anime = eventData[12]
105 rpgEvent.pages[0].direction_fix = eventData[13]
106 rpgEvent.pages[0].through = eventData[14]
107 rpgEvent.pages[0].always_on_top = eventData[15]
108 rpgEvent.pages[0].graphic = eventData[17] || rpgEvent.pages[0].graphic
109 newEvent = Game_Event.new(eventData[0],rpgEvent,$MapFactory.getMap(eventData[2]))
110 newEvent.character_name = eventData[6]
111 newEvent.character_hue = eventData[7]
112 case eventData[5] # direction
113 when 2; newEvent.turn_down # down
114 when 4; newEvent.turn_left # left
115 when 6; newEvent.turn_right # right
116 when 8; newEvent.turn_up # up
117 end
118 return newEvent
119 end
120
121 def pbEnsureEvent(event, newMapID)
122 events = $PokemonGlobal.dependentEvents
123 found = -1
124 for i in 0...events.length
125 # Check original map ID and original event ID
126 if events[i][0] == event.map_id && events[i][1] == event.id
127 # Change current map ID
128 events[i][2] = newMapID
129 newEvent = createEvent(events[i])
130
131
132 # Replace event
133 #for e in $scene.spritesetglobal.character_sprites
134 # if e.character.__id__ == @realEvents[i].__id__
135 # e.character = newEvent
136 # end
137 #end
138
139 #for p in @realEvents[i].instance_variables
140 # begin
141 # p = p.to_s#.gsub('@',"")
142 # old = @realEvents[i].instance_eval(p)
143 # new = newEvent.instance_eval(p)
144 # if old != new
145 # p(p,old,new)
146 # end
147 # rescue
148 # p(p,$!)
149 # end
150 #end
151
152 #@realEvents[i] = newEvent
153
154 @realEvents[i].instance_eval do
155 @oldMap = newEvent.instance_eval { @oldMap }
156 @map = newEvent.instance_eval { @map }
157 @stop_count = 2#newEvent.instance_eval { @stop_count }
158 @anime_count = newEvent.instance_eval { @anime_count }
159 @move_speed = newEvent.instance_eval { @move_speed }
160 @real_y = newEvent.instance_eval { @real_y }
161 @y = newEvent.instance_eval { @y }
162 @oldY = newEvent.instance_eval { @oldY }
163 @pattern = newEvent.instance_eval { @pattern }
164 end
165
166 @lastUpdate += 1
167 return i
168 end
169 end
170 return -1
171 end
172
173 # Overwrites [updateDependentEvents] to continue the algorithm with a specially
174 # given list too, rather than a common event
175 def updateDependentEvents
176 events = $PokemonGlobal.dependentEvents
177 return if events.length == 0
178 for i in 0...events.length
179 event = @realEvents[i]
180 next if !@realEvents[i]
181 event.transparent = $game_player.transparent
182 if (event.jumping? || event.moving?) || !($game_player.jumping? || $game_player.moving?) then
183 event.update
184 elsif !event.starting
185 event.set_starting
186 event.update
187 event.clear_starting
188 end
189 events[i][3] = event.x
190 events[i][4] = event.y
191 events[i][5] = event.direction
192 end
193 # Check event triggers
194 if Input.trigger?(Input::C) && !$game_temp.in_menu && !$game_temp.in_battle &&
195 !$game_player.move_route_forcing && !$game_temp.message_window_showing &&
196 !pbMapInterpreterRunning?
197 # Get position of tile facing the player
198 facingTile = $MapFactory.getFacingTile()
199 self.eachEvent do |e, d|
200 next if !d[9] && !d[16]
201 if e.x == $game_player.x && e.y == $game_player.y
202 # On same position
203 if not e.jumping? && (!e.respond_to?(:over_trigger) || e.over_trigger?)
204 if e.list.size > 1
205 # Start event
206 $game_map.refresh if $game_map.need_refresh
207 e.lock
208 pbMapInterpreter.setup(e.list,e.id,e.map.map_id)
209 end
210 end
211 elsif facingTile && e.map.map_id == facingTile[0] &&
212 e.x == facingTile[1] && e.y == facingTile[2]
213 # On facing tile
214 if not e.jumping? && (!e.respond_to?(:over_trigger) || !e.over_trigger?)
215 if e.list.size > 1
216 # Start event
217 $game_map.refresh if $game_map.need_refresh
218 e.lock
219 pbMapInterpreter.setup(e.list,e.id,e.map.map_id)
220 end
221 end
222 end
223 end
224 end
225 end
226end
227
228class DependentEventSprites
229 attr_accessor :sprites
230
231 # Overwrites [refresh] to only call [erase] on the registered events if said
232 # event objects actually have an [erase] method
233 def refresh
234 for sprite in @sprites
235 sprite.dispose
236 end
237 @sprites.clear
238 $PokemonTemp.dependentEvents.eachEvent do |event, data|
239 if data[0] == @map.map_id # Check original map
240 @map.events[data[1]].erase if @map.events[data[1]].respond_to?(:erase)
241 end
242 if data[2] == @map.map_id # Check current map
243 next if $scene.spritesetglobal.character_sprites.any? { |e| e.character.name == "Pokemon Follower" }
244 $scene.spritesetglobal.character_sprites.push(Sprite_Character.new(Spriteset_Map.viewport, event))
245 end
246 end
247 end
248end
249
250class Game_Character
251 attr_writer :x
252 attr_writer :y
253 attr_writer :real_x
254 attr_writer :real_y
255 attr_accessor :move_route
256 attr_accessor :step_anime
257 attr_accessor :direction_fix
258 attr_accessor :always_on_top
259 attr_accessor :special_list
260 attr_accessor :special_graphic
261 attr_accessor :direction
262
263 # Same as [moveto], but removes the [triggerLeaveTile] call.
264 def moveto_nocall(x, y)
265 @x = x % self.map.width
266 @y = y % self.map.height
267 @real_x = @x * Game_Map.realResX
268 @real_y = @y * Game_Map.realResY
269 @prelock_direction = 0
270 end
271end
272
273class Spriteset_Global
274 attr_reader :character_sprites
275
276 alias follower_initialize initialize
277 def initialize
278 follower_initialize
279 @character_sprites = []
280 end
281
282 alias follower_dispose dispose
283 def dispose
284 for sprite in @character_sprites
285 sprite.dispose unless sprite.disposed?
286 end
287 follower_dispose
288 end
289end
290
291class Spriteset_Map
292 attr_accessor :usersprites
293
294 alias follower_update update
295 def update
296 for sprite in $scene.spritesetglobal.character_sprites
297 if sprite.character.is_a?(Game_Event)
298 if in_range?(sprite.character) || sprite.character.move_route_forcing ||
299 sprite.character.trigger == 3 || sprite.character.trigger == 4
300 sprite.update
301 end
302 else
303 sprite.update
304 end
305 end
306 follower_update
307 end
308end
309
310class PokemonGlobalMetadata
311 attr_accessor :follower_activated
312 attr_accessor :follower_data
313 attr_accessor :follower_visible
314end
315
316class PokemonTemp
317 attr_accessor :follower_index
318 attr_accessor :follower_coming_in
319 attr_accessor :follower_coming_out
320end
321
322class Game_Player
323 attr_accessor :wasmoving
324
325 alias follower_update update
326 def update
327 follower_update
328 Follower.update
329 end
330end
331
332class Scene_Map
333 alias follower_create_spritesets createSpritesets
334 def createSpritesets
335 follower_create_spritesets
336 Follower.enable(false) if $PokemonGlobal.follower_activated
337 end
338end
339
340# Compatibility with [getConstantName]
341module PBStatuses
342 NONE = 0
343end
344
345module PBEmotions
346 ANGRY = 0
347 UPSET = 1
348 NONE = 2
349 HAPPY = 3
350 VERYHAPPY = 4
351 SAD = 5
352 EXCLAIM = 6
353 JINGLE = 7
354 LOVE = 8
355 QUESTION = 9
356 POISONED = 10
357
358 def self.getFile(emotion)
359 return [
360 "angry",
361 "upset",
362 "none",
363 "happy",
364 "very_happy",
365 "sad",
366 "exclaim",
367 "jingle",
368 "love",
369 "question",
370 "poisoned"
371 ][emotion]
372 end
373end
374
375
376# Not stored to the save file in any way; use $PokemonGlobal to keep track of
377# custom variables.
378module Follower
379 module_function
380
381 # Creates a new Follower object/sprite or reinitializes an old one if it already existed
382 def enable(animation = true)
383 unless (pbMarinUtility rescue false)
384 raise RuntimeError.new(
385 "You must have \"Marin's Utility Scripts\" installed to use the \"Marin's Pokemon Following\" resource!\n\nThe resource in question can most likely be found on Relic Castle (https://reliccastle.com/)."
386 )
387 end
388 return unless pokemon
389 return if event && sprite
390 $PokemonGlobal.follower_activated = true
391 if $PokemonGlobal.dependentEvents.size > 0 &&
392 $PokemonGlobal.dependentEvents.any? { |e| e[8] == "Pokemon Follower" }
393 # Dependent Event already exists, so fetch the object
394 de = $PokemonGlobal.dependentEvents.find { |e| e[8] == "Pokemon Follower" }
395 if de
396 list = de[16]
397 for i in 0...$PokemonTemp.dependentEvents.realEvents.size
398 if $PokemonTemp.dependentEvents.realEvents[i].event &&
399 $PokemonTemp.dependentEvents.realEvents[i].event.pages &&
400 $PokemonTemp.dependentEvents.realEvents[i].event.pages.size > 0 &&
401 $PokemonTemp.dependentEvents.realEvents[i].event.pages[0].list == list
402 # Does a bunch of trickery (the majority of which likely redundant)
403 # to get the follower in the last (x,y,dir) position as when last
404 # saved.
405 $PokemonTemp.follower_index = i
406 nx, ny, nd = $PokemonGlobal.follower_data
407 event.event.x = nx
408 event.event.y = ny
409 event.event.pages[0].graphic.direction = nd
410 event.page.graphic.direction = nd
411 event.moveto_nocall(nx, ny)
412 event.page.graphic.direction = nd
413 event.direction = nd
414 # Updates $scene.spriteset so it corrects the event's facing direction
415 # and (x,y) before it can actually display on-screen.
416 pbUpdateSceneMap
417 # If it should show an animation, it performs the animation here.
418 if animation
419 sprite.zoom_x = 0
420 sprite.zoom_y = 0
421 show
422 end
423 break
424 end
425 end
426 end
427 return
428 end
429 # Create a new follower with all properties and settings necessary to work
430 # as it should.
431 f = Game_Character.new($game_map)
432 f.character_name = update_character_name(pokemon)
433 f.x = $game_player.x + 1
434 f.y = $game_player.y
435 f.step_anime = Follower::IdleAnimation
436 # This is the command list as you'd normally create in an event in RMXP.
437 f.special_list = [
438 # Script: Follower.interact
439 RPG::EventCommand.new(355, 0, ["Follower.interact"]),
440 # Empty (dummy) event command which is apparently necessary.
441 RPG::EventCommand.new
442 ]
443 # Uses two custom properties for the sake of transferring this data easily.
444 f.special_graphic = RPG::Event::Page::Graphic.new
445 f.special_graphic.character_name = "[Dummy]"
446 r = $PokemonTemp.dependentEvents.addEvent(f, "Pokemon Follower")
447 $PokemonTemp.follower_index = r
448 $scene.spriteset.usersprites.each do |e|
449 e.refresh if e.is_a?(DependentEventSprites)
450 end
451 # Marks the follower as activated/obtained
452 $PokemonGlobal.follower_activated = true
453 # Marks the follower as invisible so it'll display the animation no matter what.
454 $PokemonGlobal.follower_visible = false
455 # If it should show an animation, it performs the animation here.
456 if animation
457 sprite.zoom_x = 0
458 sprite.zoom_y = 0
459 show
460 end
461 end
462
463 def enabled?
464 return $PokemonGlobal.follower_activated
465 end
466
467 def disabled?
468 return !enabled?
469 end
470
471 # Disables the follower and the very ability to have a following Pokémon
472 def disable(animation = true)
473 # Hides the follower with an animation if such is specified
474 hide if animation
475
476 # Disposes the sprite and removes all references to it
477 for i in 0...$scene.spritesetglobal.character_sprites.size
478 s = $scene.spritesetglobal.character_sprites[i]
479 if s.character == event
480 s.dispose
481 $scene.spritesetglobal.character_sprites.delete_at(i)
482 break
483 end
484 end
485
486 # Deletes the event and removes all references to it
487 $PokemonTemp.dependentEvents.realEvents[$PokemonTemp.follower_index] = nil
488 $PokemonTemp.dependentEvents.realEvents.delete_at($PokemonTemp.follower_index)
489 $PokemonTemp.follower_index = nil
490 for i in 0...$PokemonGlobal.dependentEvents.size
491 if $PokemonGlobal.dependentEvents[i][8] == "Pokemon Follower"
492 $PokemonGlobal.dependentEvents.delete_at(i)
493 break
494 end
495 end
496 $PokemonGlobal.follower_activated = false
497 end
498
499 # Determines the file name to use for the overworld based on a Pokémon object
500 # Tests files in a very specific order based on:
501 # - Shininess
502 # - Form
503 # - Female/Male
504 def update_character_name(poke)
505 base = poke.species.to_digits(3)
506 path = PokemonFollowingSpritePath + "/" + base
507 base = PokemonFollowingSpritePath.split('/')[2..-1].join('/') + '/' + base
508 shiny = poke.isShiny?
509 form = poke.form
510 female = poke.isFemale?
511 if shiny
512 if form > 0
513 if female
514 # Shiny, Alternate form, Female
515 # Tests files in this order:
516 # 000sf_1
517 # 000s_1
518 # 000f_1
519 # 000sf
520 # 000sf_0
521 # 000s
522 # 000s_0
523 # 000f
524 # 000f_0
525 # 000
526 # 000_0
527 if File.file?(path + "sf_#{form}.png")
528 return base + "sf_#{form}"
529 elsif File.file?(path + "s_#{form}.png")
530 return base + "s_#{form}"
531 elsif File.file?(path + "f_#{form}.png")
532 return base + "f_#{form}"
533 elsif File.file?(path + "sf.png")
534 return base + "sf"
535 elsif File.file?(path + "sf_0.png")
536 return base + "sf_0"
537 elsif File.file?(path + "s.png")
538 return base + "s"
539 elsif File.file?(path + "s_0.png")
540 return base + "s_0"
541 elsif File.file?(path + "f.png")
542 return base + "f"
543 elsif File.file?(path + "f_0.png")
544 return base + "f_0"
545 end
546 else
547 # Shiny, Alternate form, Male
548 # Tests files in this order:
549 # 000s_1
550 # 000s
551 # 000s_0
552 # 000_1
553 # 000
554 # 000_0
555 if File.file?(path + "s_#{form}.png")
556 return base + "s_#{form}"
557 elsif File.file?(path + "s.png")
558 return base + "s"
559 elsif File.file?(path + "s_0.png")
560 return base + "s_0"
561 elsif File.file?(path + "_#{form}.png")
562 return base + "_#{form}"
563 end
564 end
565 else
566 if female
567 # Shiny, Standard form, Female
568 # Tests files in this order:
569 # 000sf
570 # 000sf_0
571 # 000s
572 # 000s_0
573 # 000f
574 # 000f_0
575 # 000
576 # 000_0
577 if File.file?(path + "sf.png")
578 return base + "sf"
579 elsif File.file?(path + "sf_0.png")
580 return base + "sf_0"
581 elsif File.file?(path + "s.png")
582 return base + "s"
583 elsif File.file?(path + "s_0.png")
584 return base + "s_0"
585 elsif File.file?(path + "f.png")
586 return base + "f"
587 elsif File.file?(path + "f_0.png")
588 return base + "f_0"
589 end
590 else
591 # Shiny, Standard form, Male
592 # Tests files in this order:
593 # 000s
594 # 000s_0
595 # 000
596 # 000_0
597 if File.file?(path + "s.png")
598 return base + "s"
599 elsif File.file?(path + "s_0.png")
600 return base + "s_0"
601 end
602 end
603 end
604 else
605 if form > 0
606 if female
607 # Not Shiny, Alternate form, Female
608 # Tests files in this order:
609 # 000f_1
610 # 000f
611 # 000f_0
612 # 000_1
613 # 000
614 # 000_0
615 if File.file?(path + "f_#{form}.png")
616 return base + "f_#{form}"
617 elsif File.file?(path + "f.png")
618 return base + "f"
619 elsif File.file?(path + "f_0.png")
620 return base + "f_0"
621 elsif File.file?(path + "_#{form}.png")
622 return base + "_#{form}"
623 end
624 else
625 # Not Shiny, Alternate form, Male
626 # Tests files in this order:
627 # 000_1
628 # 000
629 # 000_0
630 if File.file?(path + "_#{form}.png")
631 return base + "_#{form}"
632 end
633 end
634 else
635 if female
636 # Not Shiny, Standard form, Female
637 # Tests files in this order:
638 # 000f
639 # 000f_0
640 # 000
641 # 000_0
642 if File.file?(path + "f.png")
643 return base + "f"
644 elsif File.file?(path + "f_0.png")
645 return base + "f_0"
646 end
647 else
648 # Not Shiny, Standard form, Male
649 # Tests files in this order:
650 # 000
651 # 000_0
652 end
653 end
654 end
655 return base if File.file?(path + ".png")
656 return base + "_0" if File.file?(path + "_0.png")
657 return nil
658 end
659
660 # The actual event object that refers to the follower
661 def event
662 return nil unless $PokemonTemp && $PokemonTemp.dependentEvents &&
663 $PokemonTemp.dependentEvents.realEvents &&
664 $PokemonTemp.follower_index
665 return $PokemonTemp.dependentEvents.realEvents[$PokemonTemp.follower_index]
666 end
667
668 # The first Pokémon of the party that should be the follower - can be nil
669 def pokemon
670 return $Trainer.party.find { |e| e.hp > 0 && !e.egg? }
671 end
672
673 # Updates the used overworld sprite in case it changes (species, shiny value, form)
674 def update
675 return unless event && sprite
676 if pokemon && (@last_id != pokemon.__id__ || @last_shiny != pokemon.isShiny? ||
677 @last_form != pokemon.form || @last_female != pokemon.isFemale?)
678 event.character_name = update_character_name(pokemon)
679 for i in 0...$PokemonGlobal.dependentEvents.size
680 if $PokemonGlobal.dependentEvents[i][8] == "Pokemon Follower"
681 $PokemonGlobal.dependentEvents[i][6] = event.character_name
682 break
683 end
684 end
685 end
686 @last_id = pokemon.__id__
687 @last_shiny = pokemon.isShiny?
688 @last_form = pokemon.form
689 @last_female = pokemon.isFemale?
690 end
691
692 # The actual Sprite_Character object associated with the follower event
693 def sprite
694 return nil unless $scene && $scene.respond_to?(:spritesetglobal) &&
695 $scene.spritesetglobal &&
696 $scene.spritesetglobal.respond_to?(:character_sprites) &&
697 $scene.spritesetglobal.character_sprites.is_a?(Array)
698 return $scene.spritesetglobal.character_sprites.find { |e| e.character == event }
699 #return nil unless $scene.respond_to?(:spriteset) &&
700 # $scene.spriteset &&
701 # $scene.spriteset.respond_to?(:usersprites) &&
702 # $scene.spriteset.usersprites.is_a?(Array)
703 #des = $scene.spriteset.usersprites.find { |e| e.is_a?(DependentEventSprites) }
704 #return nil unless des#pacito
705 #return nil unless event
706 #return des.sprites.find { |e| e.character == event }
707 end
708
709 # Whether or not the follower is currently visible
710 def visible?
711 return $PokemonGlobal.follower_visible
712 end
713
714 # Whether or not the follower is currently invisible
715 def hidden?
716 return !visible?
717 end
718
719 # Called whenever you talk to the follower. Contains the interaction table
720 # with messages it may choose from
721 def interact
722 return unless visible?
723 name = pokemon.name
724 speciesname = PBSpecies.getName(pokemon.species)
725 type = getConstantName(PBTypes,pokemon.type1) # Primary type
726 type = ":#{type}" if type
727 species = getConstantName(PBSpecies,pokemon.species) # Species name
728 species = ":#{species}" if species
729 happy = pokemon.happiness
730 status = getConstantName(PBStatuses,pokemon.status)
731 status = ":#{status}" if status
732 hp = pokemon.hp
733 hp_fact = pokemon.hp / pokemon.totalhp.to_f
734 weather = getConstantName(PBFieldWeather,$game_screen.weather_type)
735 weather = ":#{weather.upcase}" if weather
736 outside = pbGetMetadata($game_map.map_id, MetadataOutdoor)
737 msg = []
738 emote = proc do |emotion|
739 msg.map! do |e|
740 if e.is_a?(String)
741 next [emotion, [e]]
742 elsif e.is_a?(Array) && e[0].is_a?(String)
743 next [emotion, e]
744 else
745 next e
746 end
747 end
748 end
749
750 if status != :NONE # If the Pokémon has one of the status conditions below
751 if hp_fact < 0.25 # HP less than 25%
752 msg << _INTL("[P] is dizzy.")
753 msg << _INTL("[P] is going to fall down!")
754 msg << _INTL("[P] seems about to fall over!")
755 emote.call(PBEmotions::SAD)
756 elsif hp_fact < 0.5 # HP less than 50%
757 msg << _INTL("[P] is trying very hard to keep up with you...")
758 msg << _INTL("[P] seems a little tired.")
759 emote.call(PBEmotions::SAD)
760 end
761 if status == :BURN # Is burned
762 msg << _INTL("[P]'s burn looks painful!")
763 emote.call(PBEmotions::SAD)
764 elsif status == :PARALYSIS # Has paralysis
765 msg << _INTL("[P] is trying very hard to keep up with you...")
766 emote.call(PBEmotions::SAD)
767 elsif status == :POISON # Is poisoned
768 msg << _INTL("[P] is shivering with the effects of being poisoned.")
769 emote.call(PBEmotions::POISONED)
770 elsif status == :FROZEN # Is frozen
771 msg << [_INTL("[P] seems very cold...")]
772 msg << _INTL("...Your Pokémon seems a little cold.")
773 emote.call(PBEmotions::SAD)
774 end
775 end
776 no_status_messages = msg.size == 0
777 if happy < 50 || happy >= 100 # All emotions but UPSET (0-50, 100-255)
778 if type == :FIRE && weather == :RAIN
779 msg << _INTL("[P] is not happy.")
780 msg << _INTL("[P] is stepping on your feet!")
781 emote.call(PBEmotions::SAD)
782 end
783 end
784 r = rand(100) + 1 # Random 1 - 100
785 if happy >= 70 # Only if happiness is greater than or equal to 70 (default catch happiness)
786 if r <= 15 # 15%
787 msg << _INTL("[P] suddenly started walking closer!")
788 if name.ends_with?('s') # ['s] vs [s']
789 msg << _INTL("[P]' cheeks are becoming rosy!")
790 else
791 msg << _INTL("[P]'s cheeks are becoming rosy!")
792 end
793 msg << _INTL("Whoa! [P] suddenly hugged you!")
794 msg << [_INTL("[P] nudged {1}, nudge back?", $Trainer.name), [
795 ["Yes", _INTL("Your Pokémon is shouting happily!"), PBEmotions::EXCLAIM],
796 ["No", _INTL("Your Pokémon seems a bit bored."), PBEmotions::NONE]
797 ], 1]
798 msg << _INTL("Whoa! [P] is suddenly playful!")
799 msg << _INTL("[P] is rubbing against your legs!")
800 msg << _INTL("[P] blushed.")
801 msg << _INTL("Ah! [P] cuddled you!")
802 msg << _INTL("[P] is regarding you with adoration!")
803 msg << _INTL("[P] got closer to {1}!", $Trainer.name)
804 msg << _INTL("[P] is keeping close to your feet.")
805 emote.call(PBEmotions::LOVE)
806 elsif r <= 25 # Another 10%
807 msg << _INTL("[P] is showing off its agility!")
808 msg << _INTL("[P] is moving around happily!")
809 msg << _INTL("Whoa! [P] suddenly started dancing in happiness!")
810 msg << _INTL("[P] is steadily keeping up with you!")
811 msg << _INTL("[P] is happy skipping about.")
812 msg << _INTL("[P] is singing and humming.")
813 msg << _INTL("[P] is playfully nibbling at the ground")
814 msg << _INTL("[P] is nipping at your feet!")
815 msg << _INTL("[P] turned around and looked at you.")
816 msg << _INTL("[P] is working hard to show off its mighty power!")
817 msg << _INTL("Whoa! [P] suddenly danced in happiness!")
818 msg << _INTL("[P] is cheeful!")
819 msg << [_INTL("[P] is following you very closely! Do you want to give it a pat?"), [
820 ["Yes", _INTL("Waah! Your Pokémon is acting very surprised!"), PBEmotions::EXCLAIM],
821 ["No", _INTL("Your Pokémon is so very angry!"), PBEmotions::ANGRY]
822 ], 1]
823 msg << _INTL("[P] is jumping around in a carefree way!")
824
825 if outside
826 msg << _INTL("[P] is pulling out the grass")
827 msg << _INTL("[P] is looking up at the sky.")
828 msg << _INTL("[P] is clawing the grass!")
829 msg << _INTL("[P] is rolling around in the grass.")
830 msg << _INTL("[P] is playing around with a leaf.")
831 msg << _INTL("[P] is noticing the scent of the grass.")
832 msg << _INTL("[P] is playing around, plucking bits of grass.")
833 msg << _INTL("[P] is happy to see what's outdoors!")
834 if PBDayNight.isNight? # If at night
835 msg << _INTL("Your Pokémon is staring spellbound at the night sky!")
836 end
837 else # Inside
838 msg << _INTL("[P] is looking up at the ceiling.")
839 end
840 if weather == :RAIN # Is raining
841 msg << _INTL("[P] is very happy about the rain.")
842 msg << _INTL("[P] is playing in a puddle.")
843 if ![:GROUND, :FIRE, :ROCK].include?(type)
844 msg << _INTL("[P] seems to be happy about the rain!")
845 end
846 end
847 emote.call(PBEmotions::JINGLE)
848 elsif r <= 30 # Another 5%
849 msg << _INTL("[P] is in danger of falling over!")
850 msg << _INTL("[P] bumped into {1}!", $Trainer.name)
851 msg << _INTL("[P] is perring down.")
852 msg << _INTL("Your Pokémon stumbled and nearly fell!")
853 msg << _INTL("[P] seems refreshed!")
854 msg << _INTL("[P] seems to have found something!")
855 msg << _INTL("[P] suddenly turned around and started barking!")
856 msg << _INTL("[P] suddenly turned around!")
857 msg << _INTL("Your Pokémon was surprised that you suddenly spoke to it!")
858 msg << _INTL("[P] feels refreshed.")
859 msg << _INTL("[P] is wobbling and seems about to fall over!")
860 msg << _INTL("[P] is walking along cautiously.")
861 msg << _INTL("[P] is getting tense with nervous energy!")
862 msg << _INTL("[P] sensed something strange and was surprised!")
863 msg << _INTL("[P] is scared and snuggled up to {1}!", $Trainer.name)
864 msg << _INTL("[P] is feeling an unusual presence...")
865
866 if pokemon.item > 0 # Is holding an item
867 msg << _INTL("[P] almost forgot it was holding that {1}!", PBItems.getName(pokemon.item))
868 end
869 if weather == :RAIN # Is raining
870 msg << _INTL("[P] seems to be very surprised that it is raining!")
871 end
872 if outside # Outside map
873 msg << _INTL("[P] seems to have gotten caught in the clumps of grass!")
874 msg << _INTL("[P] looked up at the sky and shouted loudly!")
875 msg << _INTL("A cold wind suddenly blew by!")
876 else # Indoor
877 msg << _INTL("[P] slipped on the floor and seems likely to fall!")
878 end
879 if name != speciesname
880 msg << _INTL("[P] doesn't seem to be used to its own name yet.")
881 end
882 emote.call(PBEmotions::EXCLAIM)
883 elsif r <= 40 # Another 10%
884 msg << _INTL("Your Pokémon is looking around restlessly for something.")
885 msg << _INTL("Your Pokémon wasn't watching where it was going and ran into you!")
886 msg << _INTL("Sniff, sniff! Is something nearby?")
887 msg << [_INTL("[P] is holding something, do you want to take it?"), [
888 ["Yes", _INTL("Oh! It seems just too important to let go!"), PBEmotions::ANGRY],
889 ["No", _INTL("[P] seems happy to have found something!")]
890 ], 1]
891 msg << [_INTL("[P] is holding something, do you want to take it?"), [
892 ["Yes", _INTL("[P] happily handed it over!"), PBEmotions::JINGLE],
893 ["No", _INTL("[P] seems happy to have found something!")]
894 ], 1]
895 msg << _INTL("[P] is wandering around and searching for something...")
896 msg << _INTL("[P] is sniffling at {1}.", $Trainer.name)
897 msg << _INTL("[P] seems to be a little hesitant...")
898 msg << [_INTL("[P] is heading your way with something in its mouth. Take the item out of its mouth?"), [
899 ["Yes", _INTL("Your Pokémon seems sad..."), PBEmotions::SAD],
900 ["No", _INTL("[P] seems happy to have found something!")]
901 ], 1]
902
903 if outside # Outside map
904 msg << _INTL("[P] is rolling a pebble around.")
905 end
906 emote.call(PBEmotions::QUESTION)
907 end
908 end
909 # If there aren't any messaged yet that would be displayed when you have
910 # one of the status conditions defined above. This way, it will not
911 # allow for happiness-related messages if you have one of the conditions.
912 if no_status_messages
913 case happy
914 when 0...50
915 msg << _INTL("[P] let out a roar!")
916 msg << _INTL("[P] is making a face like it's angry!")
917 msg << _INTL("[P] seems to be angry for some reason.")
918 msg << [_INTL("Your Pokémon turned to face the other way, showing a defiant expression."),
919 proc { event.direction = 10 - event.direction }
920 ]
921 msg << [_INTL("[P] chewed on your feet, scold it?"), [
922 ["Yes", _INTL("Your Pokémon seems to be a bit dispondant...")],
923 ["No", _INTL("Your Pokémon ate something that tasted bad and is trying to spit it out!"), PBEmotions::SAD]
924 ], 1]
925 msg << _INTL("[P] cried out!")
926 emote.call(PBEmotions::ANGRY)
927 when 50...100
928 if type == :FIRE && weather == :RAIN && outside # Is Fire type and is raining
929 msg << _INTL("[P] is taking shelter in the grass from the rain.")
930 msg << _INTL("[P] is splashing around in the wet grass.")
931 msg << _INTL("Your Pokémon doesn't like splashing around on the ground.")
932 end
933 msg << _INTL("[P] seems unhappy somehow...")
934 msg << _INTL("[P] seems to feel a little claustrophobic.")
935 msg << _INTL("[P] is a bit nervous about the narrow space!")
936 msg << _INTL("[P] is making an unhappy face.")
937 msg << _INTL("[P] seems uneasy and is poking {1}!", $Trainer.name)
938 msg << [_INTL("[P] wants your attention now! Want to play along?"), [
939 ["Yes", _INTL("Your Pokémon seems to be having fun!"), PBEmotions::JINGLE],
940 ["No", _INTL("Your Pokémon is grumbling because it wants you to pay more attention to it!")]
941 ], 1]
942 msg << [_INTL("[P] seems a bit uneasy and is shuffling around nervously, say something?"), [
943 ["Yes", _INTL("[P] feels safer just by seeing {1}'s face.", $Trainer.name)],
944 ["No", _INTL("Oh! Your Pokémon seems about to fall...")],
945 ], 1]
946 emote.call(PBEmotions::UPSET)
947 when 100...150
948 msg << _INTL("[P] is looking down steadily.")
949 msg << [_INTL("[P] is blankly staring in your direction... Do you want to call its name?"), [
950 ["Yes", _INTL("Your Pokémon seems so happy!"), PBEmotions::VERYHAPPY],
951 ["No", _INTL("Your Pokémon is in a daze."), PBEmotions::NONE]
952 ], 1]
953 msg << _INTL("[P] is surveying the area.")
954 msg << _INTL("[P] is sniffling at the floor.")
955 msg << _INTL("[P] is peering down.")
956 msg << [_INTL("[P] is looking nervous. Would you like to say something?"), [
957 ["Yes", _INTL("[P] seems shocked!"), PBEmotions::EXCLAIM],
958 ["No", _INTL("Your Pokémon appears to be somewhat hardened and unable to move.")]
959 ], 1]
960 msg << _INTL("[P] seems to be wandering around.")
961 msg << _INTL("[P] is looking around absentmindedly.")
962 msg << _INTL("[P] yawned very loudly!")
963 msg << _INTL("[P] is relaxing comfortably.")
964 msg << _INTL("[P] is staring steadfastly at {1}'s face.", $Trainer.name)
965 msg << _INTL("[P] is staring intently at {1}'s face.", $Trainer.name)
966 msg << _INTL("[P] is focusing its attention on you.")
967 msg << _INTL("[P] is staring into the depths.")
968 msg << _INTL("Your Pokémon is staring intently at nothing.")
969 msg << [_INTL("Your Pokémon turned to face the other way, showing a defiant expression."),
970 proc { event.direction = 10 - event.direction }
971 ]
972 msg << _INTL("[P] focused with a sharp gaze!")
973 msg << [_INTL("[P] seems a bit nervous, do you want to say something?"), [
974 ["Yes", _INTL("Waah! Your Pokémon is acting very surprised!"), PBEmotions::EXCLAIM],
975 ["No", _INTL("Your Pokémon appears to be somewhat hardened and unable to move.")]
976 ], 1]
977 msg << _INTL("[P] is concentrating.")
978 msg << _INTL("[P] faced your way and nodded.")
979 msg << _INTL("[P] seems a bit nervous...")
980 msg << _INTL("[P] is looking at {1}'s footprints.", $Trainer.name)
981 msg << _INTL("[P] is staring straight into {1}'s eyes.", $Trainer.name)
982 msg << [_INTL("[P] seems to want to play and is gazing at you expectedly, will you give in?"), [
983 ["Yes", _INTL("Your Pokémon is indescribably happy!"), PBEmotions::JINGLE],
984 ["No", _INTL("Oh! Your Pokémon seems about to cry!"), PBEmotions::SAD]
985 ], 1]
986 msg << [_INTL("Your Pokémon is gazing restlessly at you as if it wants to play, will you give in?"), [
987 ["Yes", _INTL("Your Pokémon jumped around happily!"), PBEmotions::JINGLE],
988 ["No", _INTL("Oh! Your Pokémon seems about to cry!"), PBEmotions::SAD]
989 ], 1]
990 if outside # Outside map
991 msg << _INTL("[P] seems to relax as it hears of rustling leaves...")
992 msg << _INTL("[P] seems to be listening to the sound of rustling leaves...")
993 end
994 if type == :FIRE # Is a fire type
995 msg << _INTL("[P] emitted fire and shouted!")
996 end
997 if status == :SLEEP # Is asleep
998 msg << _INTL("[P] is somehow fighting off sleep...")
999 end
1000 emote.call(PBEmotions::NONE)
1001 when 150...256
1002 msg << _INTL("[P] began poking you in the stomach!")
1003 msg << _INTL("[P] is happy but shy.")
1004 msg << _INTL("[P] is coming along happily.")
1005 msg << _INTL("[P] is composed!")
1006 msg << _INTL("[P] seems to be feeling great about walking with you!")
1007 msg << _INTL("[P] looks very happy!")
1008 msg << _INTL("[P] put in extra effort!")
1009 msg << _INTL("[P] is smelling the scents of the surrounding air.")
1010 msg << _INTL("[P] is jumping for joy!")
1011 msg << _INTL("[P] is still feeling great!")
1012 msg << _INTL("[P] is poking at your belly!")
1013 msg << _INTL("Your Pokémon stretched out its body and is relaxing.")
1014 msg << _INTL("[P] looks like it wants to lead!")
1015 msg << _INTL("[P] is doing its best to keep up with you!")
1016 msg << _INTL("[P] is happily cuddling up to you!")
1017 msg << _INTL("[P] seems to be very happy!")
1018 msg << _INTL("[P] is so happy that it can't stand still!")
1019 msg << _INTL("[P] nodded slowly.")
1020 msg << _INTL("[P] is wandering around and listening to the different sounds.")
1021 msg << _INTL("[P] looks very interested.")
1022 msg << _INTL("[P] gave you a sunny look!")
1023 msg << _INTL("[P] gave you a happy look and a smile!")
1024 msg << _INTL("[P] seems very happy to see you!")
1025 msg << _INTL("[P] faced your way and grinned.")
1026 msg << _INTL("[P] happily cuddled up to you!")
1027
1028 if hp_fact >= 0.5 # More than 50% health
1029 msg << _INTL("[P] is glowing with health!")
1030 msg << _INTL("[P] is full of life!")
1031 else # LESS than 50% health
1032 msg << _INTL("[P] is somehow forcing itself to keep going.")
1033 end
1034 if weather != :RAIN # NOT raining
1035 msg << _INTL("Your Pokémon seems happy about the great weather.")
1036 end
1037 if outside # Outside map
1038 msg << _INTL("Your Pokémon is smelling the scent of flowers.")
1039 end
1040 emote.call([PBEmotions::HAPPY,PBEmotions::VERYHAPPY][rand(2)])
1041 end
1042 end
1043
1044 r = rand(msg.size)
1045 msg = msg[r]
1046 e = msg[0]
1047 msg = msg[1]
1048 txt = msg[0].gsub(/\[P\]/, name)
1049 code = msg[1] if msg[1].is_a?(Proc)
1050 choices = msg[1] if msg[1].is_a?(Array)
1051 default = msg[2] if msg[2] && msg[2].is_a?(Numeric)
1052
1053 if code
1054 code.call
1055 pbUpdateSceneMap
1056 end
1057 sprite.emotion(e)
1058 while sprite.emotion_playing?
1059 Graphics.update
1060 Input.update
1061 pbUpdateSceneMap
1062 end
1063 if choices
1064 idx = Kernel.pbMessage(txt, choices.map { |e| e[0] }, -1, nil, 0)
1065 idx = default if idx == -1
1066 txt = choices[idx][1].gsub(/\[P\]/, name)
1067 e = nil
1068 e = choices[idx][2] if choices[idx][2]
1069 sprite.emotion(e) if e
1070 while sprite.emotion_playing?
1071 Graphics.update
1072 Input.update
1073 pbUpdateSceneMap
1074 end
1075 Kernel.pbMessage(txt)
1076 else
1077 Kernel.pbMessage(txt)
1078 end
1079 end
1080
1081 # Toggles the visibility of the follower
1082 def toggle
1083 return unless event && sprite && !$PokemonTemp.follower_coming_in &&
1084 !$PokemonTemp.follower_coming_out
1085 return if $game_player.moving? || $game_player.wasmoving
1086 if visible?
1087 hide
1088 else
1089 show
1090 end
1091 end
1092
1093 # Hides the follower sprite (retraction, coming in)
1094 def hide
1095 return unless $PokemonGlobal.follower_visible
1096 $PokemonTemp.follower_coming_in = true
1097 ball = Sprite.new(sprite.viewport)
1098 ball.bitmap = Bitmap.new("Graphics/Characters/Following Pokemon/Balls/ball")
1099 ball.x = sprite.x
1100 ball.y = sprite.y + 8
1101 ball.ox = ball.bitmap.width / 2
1102 ball.oy = ball.bitmap.height
1103 ball.z = sprite.z - 1
1104 ball.opacity = 0
1105 n = 1
1106 2.times do
1107 Graphics.update
1108 Input.update
1109 pbUpdateSceneMap
1110 sprite.zoom_x = 1
1111 sprite.zoom_y = 1
1112 ball.opacity += 128
1113 end
1114 9.times do |i|
1115 Graphics.update
1116 Input.update
1117 pbUpdateSceneMap
1118 sprite.color = Color.new(255,255,255,255 * (i / 9.0))
1119 n -= 1 / 9.0
1120 if n == 3
1121 if sprite.respond_to?(:shadow) && sprite.shadow
1122 sprite.shadow.visible = false
1123 end
1124 end
1125 sprite.zoom_x = n
1126 sprite.zoom_y = n
1127 end
1128 sprite.visible = false
1129 ball.dispose
1130 sprite.visible = false
1131 $PokemonTemp.follower_coming_in = false
1132 $PokemonGlobal.follower_visible = false
1133 end
1134
1135 # Shows the follower sprite (coming out)
1136 def show
1137 return if $PokemonGlobal.follower_visible
1138 $PokemonTemp.follower_coming_out = true
1139 ball = Sprite.new(sprite.viewport)
1140 ball.bmp("Graphics/Characters/Following Pokemon/Balls/ball")
1141 ball.x = sprite.x
1142 ball.y = sprite.y + 8
1143 ball.ox = ball.bmp.width / 2
1144 ball.oy = ball.bmp.height
1145 ball.z = sprite.z - 1
1146 ball.opacity = 0
1147 2.times do
1148 Graphics.update
1149 Input.update
1150 pbUpdateSceneMap
1151 sprite.zoom_x = 0
1152 sprite.zoom_y = 0
1153 ball.opacity += 128
1154 end
1155 a = Sprite.new(sprite.viewport)
1156 a.bmp("Graphics/Characters/Following Pokemon/animation")
1157 a.src_rect.width = a.bmp.width / 4
1158 a.src_rect.x = -a.src_rect.width
1159 a.x = ball.x
1160 a.y = ball.y + 4
1161 a.ox = a.src_rect.width / 2
1162 a.oy = a.bmp.height
1163 a.z = sprite.z + 1
1164 n = 0
1165 9.times do |i|
1166 Graphics.update
1167 Input.update
1168 pbUpdateSceneMap
1169 sprite.color = Color.new(255,255,255,255 * ((9 - i) / 9.0))
1170 n += 1 / 9.0
1171 sprite.zoom_x = n
1172 sprite.zoom_y = n
1173 if i > 0 && i % 2 == 0
1174 a.src_rect.x += a.src_rect.width
1175 end
1176 end
1177 2.times do
1178 Graphics.update
1179 Input.update
1180 pbUpdateSceneMap
1181 ball.opacity -= 128
1182 end
1183 ball.dispose
1184 a.dispose
1185 sprite.visible = false
1186 $PokemonTemp.follower_coming_out = false
1187 $PokemonGlobal.follower_visible = true
1188 end
1189end
1190
1191class Sprite_Character
1192 # Aliases [update] to allow for different [zoom_x] and [zoom_y] values
1193 alias follower_update update
1194 def update
1195 oldzx = self.zoom_x
1196 oldzy = self.zoom_y
1197 follower_update
1198 if Follower.event && @character == Follower.event && (oldzx != self.zoom_x ||
1199 oldzy != self.zoom_y)
1200 self.zoom_x = oldzx
1201 self.zoom_y = oldzy
1202 end
1203 # OW Shadows support
1204 @shadow.visible = false if @shadow && (self.zoom_x <= 0 || self.zoom_y <= 0)
1205 return unless @i
1206 case @i
1207 when 0...6
1208 @emotion.y -= 4
1209 when 6...10
1210 @emotion.y += 4
1211 @emotion.src_rect.x += @emotion.src_rect.width if @i == 9
1212 when 18
1213 @emotion.src_rect.x = 0
1214 when 26
1215 @emotion.src_rect.x += @emotion.src_rect.width
1216 when 46
1217 @emotion.dispose
1218 @emotion = nil
1219 @i = nil
1220 end
1221 @i += 1 if @i
1222 end
1223
1224 # Plays the given emotion (PBEmotion, integer)
1225 def emotion(e)
1226 @emotion = Sprite.new(@viewport)
1227 @emotion.bmp("Graphics/Characters/Following Pokemon/Emotions/#{PBEmotions.getFile(e)}")
1228 @emotion.src_rect.width = 30
1229 @emotion.x = self.x
1230 @emotion.y = self.y - 46
1231 @emotion.z = self.z + 2
1232 @emotion.ox = @emotion.src_rect.width / 2
1233 @emotion.oy = @emotion.bmp.height
1234 @i = 0
1235 end
1236
1237 # Returns whether or not the emotion is (still) playing
1238 def emotion_playing?
1239 return !@emotion.nil?
1240 end
1241
1242 # Refreshes the direction value
1243 def refresh
1244 sx = @character.pattern * @cw
1245 sy = ((@character.direction - 2) / 2) * @ch
1246 self.src_rect.set(sx, sy, @cw, @ch)
1247 self.oy = (@spriteoffset rescue false) ? @ch - 16 : @ch
1248 self.oy -= @character.bob_height
1249 end
1250end
1251
1252# Toggles the follower when pressing Control
1253class << Input
1254 alias follower_update update
1255 def update
1256 follower_update
1257 # Same conditions as for moving the main player character - if you can't move,
1258 # you can't toggle your follower.
1259 return unless $game_player && $game_system && $PokemonTemp && $PokemonGlobal
1260 unless $game_player.moving? or $game_system.map_interpreter.running? or
1261 $game_player.move_route_forcing or $game_temp.message_window_showing or
1262 $PokemonTemp.miniupdate
1263 if Input.trigger?(Input::CTRL)
1264 Follower.toggle
1265 end
1266 end
1267 end
1268end
1269
1270# Overwrites the save function to add some more data to the save file regarding
1271# the follower's position/direction
1272alias follower_save pbSave
1273def pbSave(*args)
1274 e = Follower.event
1275 if e
1276 $PokemonGlobal.follower_data = [e.x, e.y, e.direction]
1277 nx, ny, nd = [e.x, e.y, e.direction]
1278 e.event.x = nx
1279 e.event.y = ny
1280 e.event.pages[0].graphic.direction = nd
1281 e.x, e.y, e.page.graphic.direction = nx, ny, nd
1282 end
1283 follower_save(*args)
1284end
1285
1286#==============================================================================#
1287# * PASSABILITY #
1288#==============================================================================#
1289
1290class Game_Map
1291 alias follower_passable? passable?
1292 def passable?(x, y, d, self_event = nil)
1293
1294 return follower_passable?(x, y, d, self_event)
1295 end
1296
1297 alias follower_passableStrict? passableStrict?
1298 def passableStrict?(x, y, d, self_event = nil)
1299 return false if !valid?(x, y)
1300
1301 # Implements bridges for the follower
1302 for i in [2, 1, 0]
1303 tile_id = data[x, y, i]
1304 tag = nil
1305 tag = @terrain_tags[tile_id] if tile_id
1306 if tag == PBTerrain::Bridge && self_event && self_event == Follower.event
1307 return true
1308 end
1309 end
1310
1311 for event in events.values
1312 if event.tile_id >= 0 and event != self_event and
1313 event.x == x and event.y == y and not event.through
1314 if @terrain_tags[event.tile_id]!=PBTerrain::Neutral
1315 return false if @passages[event.tile_id] & 0x0f != 0
1316 return true if @priorities[event.tile_id] == 0
1317 end
1318 end
1319 end
1320
1321 # Changed the regular passability check to support non-4-dir tile passabilities
1322 # as well (commonly used for bridges, for instance)
1323 bit = (1 << (d / 2 - 1)) & 0x0F
1324 for i in [2, 1, 0]
1325 tile_id = data[x, y, i]
1326 if @terrain_tags[tile_id] != PBTerrain::Neutral
1327 if @passages[tile_id] & bit != 0 ||
1328 @passages[tile_id] & 0x0f == 0x0f
1329 return false
1330 elsif @priorities[tile_id] == 0
1331 return true
1332 end
1333 end
1334 end
1335 return true
1336 end
1337end
1338
1339class DependentEvents
1340 def pbFollowEventAcrossMaps(leader, follower, instant = false,
1341 leaderIsTrueLeader = true)
1342 d = leader.direction
1343 areConnected = $MapFactory.areConnected?(leader.map.map_id, follower.map.map_id)
1344 # Get the rear facing tile of leader
1345 facingDirection=[0,0,8,0,6,0,4,0,2][d]
1346 if !leaderIsTrueLeader && areConnected
1347 relativePos = $MapFactory.getThisAndOtherEventRelativePos(leader, follower)
1348 if (relativePos[1] == 0 && relativePos[0] == 2) # 2 spaces to the right of leader
1349 facingDirection = 6
1350 elsif (relativePos[1] == 0 && relativePos[0] == -2) # 2 spaces to the left of leader
1351 facingDirection = 4
1352 elsif relativePos[1] == -2 && relativePos[0] == 0 # 2 spaces above leader
1353 facingDirection = 8
1354 elsif relativePos[1] == 2 && relativePos[0] == 0 # 2 spaces below leader
1355 facingDirection = 2
1356 end
1357 end
1358 facings = [facingDirection] # Get facing from behind
1359 facings.push([0,0,4,0,8,0,2,0,6][d]) # Get right facing
1360 facings.push([0,0,6,0,2,0,8,0,4][d]) # Get left facing
1361 if !leaderIsTrueLeader
1362 facings.push([0,0,2,0,4,0,6,0,8][d]) # Get forward facing
1363 end
1364 mapTile = nil
1365 if areConnected
1366 bestRelativePos = -1
1367 oldthrough = follower.through
1368 follower.through = false
1369 for i in 0...facings.length
1370 facing = facings[i]
1371 tile = $MapFactory.getFacingTile(facing, leader)
1372 passable = tile && $MapFactory.isPassableStrict?(tile[0], tile[1], tile[2], follower)
1373 if i == 0 && !passable && tile &&
1374 PBTerrain.isLedge?($MapFactory.getTerrainTag(tile[0], tile[1], tile[2]))
1375 # If the tile isn't passable and the tile is a ledge,
1376 # get tile from further behind
1377 tile = $MapFactory.getFacingTileFromPos(tile[0], tile[1], tile[2], facing)
1378 passable = tile && $MapFactory.isPassableStrict?(tile[0], tile[1], tile[2], follower)
1379 end
1380 if passable
1381 relativePos = $MapFactory.getThisAndOtherPosRelativePos(follower,
1382 tile[0], tile[1], tile[2])
1383 distance = Math.sqrt(relativePos[0] ** 2 + relativePos[1] ** 2)
1384 if bestRelativePos == -1 || bestRelativePos > distance
1385 bestRelativePos = distance
1386 mapTile = tile
1387 end
1388 if i == 0 && distance <= 1 # Prefer behind if tile can move up to 1 space
1389 break
1390 end
1391 end
1392 end
1393 follower.through = oldthrough
1394 else
1395 tile = $MapFactory.getFacingTile(facings[0], leader)
1396 passable = tile && $MapFactory.isPassableStrict?(tile[0], tile[1], tile[2], follower)
1397 mapTile = passable ? mapTile : nil
1398 end
1399 if mapTile && follower.map.map_id == mapTile[0]
1400 # Follower is on same map
1401 newX = mapTile[1]
1402 newY = mapTile[2]
1403 deltaX = (d == 6 ? -1 : d == 4 ? 1 : 0)
1404 deltaY = (d == 2 ? -1 : d == 8 ? 1 : 0)
1405 posX = newX + deltaX
1406 posY = newY + deltaY
1407 follower.move_speed = leader.move_speed # sync movespeed
1408 if (follower.x - newX == -1 && follower.y == newY) ||
1409 (follower.x - newX == 1 && follower.y == newY) ||
1410 (follower.y - newY == -1 && follower.x == newX) ||
1411 (follower.y - newY == 1 && follower.x == newX)
1412 if instant
1413 follower.moveto(newX, newY)
1414 else
1415 pbFancyMoveTo(follower, newX, newY)
1416 end
1417 elsif (follower.x - newX == -2 && follower.y == newY) ||
1418 (follower.x - newX == 2 && follower.y == newY) ||
1419 (follower.y - newY == -2 && follower.x == newX) ||
1420 (follower.y - newY == 2 && follower.x == newX)
1421 if instant
1422 follower.moveto(newX, newY)
1423 else
1424 pbFancyMoveTo(follower, newX, newY)
1425 end
1426 elsif follower.x != posX || follower.y != posY
1427 if instant
1428 follower.moveto(newX, newY)
1429 else
1430 pbFancyMoveTo(follower, posX, posY)
1431 pbFancyMoveTo(follower, newX, newY)
1432 end
1433 end
1434 pbTurnTowardEvent(follower, leader)
1435 else
1436 if !mapTile
1437 # Make current position into leader's position
1438 mapTile = [leader.map.map_id, leader.x, leader.y]
1439 end
1440 if follower.map.map_id == mapTile[0]
1441 # Follower is on same map as leader
1442 follower.moveto(leader.x, leader.y)
1443 pbTurnTowardEvent(follower, leader)
1444 else
1445 # Follower will move to different map
1446 events = $PokemonGlobal.dependentEvents
1447 eventIndex = pbEnsureEvent(follower, mapTile[0])
1448 if eventIndex >= 0
1449 newFollower = @realEvents[eventIndex]
1450 newEventData = events[eventIndex]
1451 newFollower.moveto(mapTile[1], mapTile[2])
1452 newEventData[2] = mapTile[0]
1453 newEventData[3] = mapTile[1]
1454 newEventData[4] = mapTile[2]
1455
1456
1457 # Tweaks a few values to ensure the follower transition from
1458 # map A to map B is smoother.
1459 running = $game_player.pbCanRun?
1460
1461=begin
1462
1463 newFollower.real_x = $game_player.real_x
1464 if d == 4
1465 if running
1466 newFollower.real_x += Game_Map.realResX - (2 ** $game_player.move_speed) / 0.58
1467 else
1468 newFollower.real_x += Game_Map.realResX - (2 ** $game_player.move_speed) / 5.0
1469 end
1470 elsif d == 6
1471 if running
1472 newFollower.real_x -= Game_Map.realResX - (2 ** $game_player.move_speed) / 0.58
1473 else
1474 newFollower.real_x -= Game_Map.realResX - (2 ** $game_player.move_speed) / 5.0
1475 end
1476 end
1477
1478=end
1479
1480 newFollower.real_y = $game_player.real_y
1481 if d == 8
1482 if running
1483 newFollower.real_y += Game_Map.realResY - (2 ** $game_player.move_speed) / 0.58
1484 else
1485 newFollower.real_y += Game_Map.realResY - (2 ** $game_player.move_speed) / 5.0
1486 end
1487 elsif d == 2
1488 if running
1489 newFollower.real_y -= Game_Map.realResY - (2 ** $game_player.move_speed) / 0.58
1490 else
1491 newFollower.real_y -= Game_Map.realResY - (2 ** $game_player.move_speed) / 5.0
1492 end
1493 end
1494
1495#=end
1496
1497 if mapTile[0] == leader.map.map_id
1498 pbTurnTowardEvent(follower, leader)
1499 end
1500 end
1501 end
1502 end
1503 end
1504end