Final Fantasy X Sphere Grid
Version 1.0
Author Feoden
Release Date 6th March 2012
Introduction I have eventually decided to release the Sphere Grid system. I hope it will enjoy you, it is almost identical to the original one, and FFX fans might appreciate this a lot
Features The script features a fully functional sphere grid. All spheres included in FFX have been inserted and tested. You can learn skills (4 kinds of skills), you can increase your stats, erase locks, fill empty spaces and remove weak slots! and also, you can use teleport spheres to go anywhere you wish!

It also allows to have characters that do not use sphere grid. Just do not add them in the ACTORS hash, and they will be normal characters.
Those who are included can use all the sphere grid features (explained below).
Script [spoiler="Script pages"]
This is where actors are modified.
CODE
class Tidus < Game_Actor
attr_accessor :turbopts
attr_accessor :turbotype
attr_accessor :ap
attr_accessor :current_node
attr_reader :level_max
attr_accessor :level_used
attr_reader :grid_color
def setup(actor_id)
@ap = 0
@ap_increase = 200
@ap_linear = 40000
@turbopts=0
@turbotype = 1
@turbomax = 1000
@level_max = 0
@level_used = 0
super(actor_id)
@current_node = RPG::ACTORS[actor_id][1]
@grid_color = RPG::ACTORS[actor_id][0]
end
#--------------------------------------------------------------------------
def base_maxhp
n = $data_actors[@actor_id].parameters[0, @level]
if $game_party == nil
return n
end
for node in $game_party.nodes
if node.type == 5 and node.learnset[@actor_id]
n += node.value
end
end
return n
end
#--------------------------------------------------------------------------
def base_maxsp
n = $data_actors[@actor_id].parameters[1, @level]
if $game_party == nil
return n
end
for node in $game_party.nodes
if node.type == 6 and node.learnset[@actor_id]
n += node.value
end
end
return n
end
#--------------------------------------------------------------------------
def base_str
n = $data_actors[@actor_id].parameters[2, @level]
weapon = $data_weapons[@weapon_id]
armor1 = $data_armors[@armor1_id]
armor2 = $data_armors[@armor2_id]
armor3 = $data_armors[@armor3_id]
armor4 = $data_armors[@armor4_id]
n += weapon != nil ? weapon.str_plus : 0
n += armor1 != nil ? armor1.str_plus : 0
n += armor2 != nil ? armor2.str_plus : 0
n += armor3 != nil ? armor3.str_plus : 0
n += armor4 != nil ? armor4.str_plus : 0
for node in $game_party.nodes
if node.type == 7 and node.learnset[@actor_id]
n += node.value
end
end
return [[n, 1].max, 999].min
end
#--------------------------------------------------------------------------
def base_dex
n = $data_actors[@actor_id].parameters[3, @level]
weapon = $data_weapons[@weapon_id]
armor1 = $data_armors[@armor1_id]
armor2 = $data_armors[@armor2_id]
armor3 = $data_armors[@armor3_id]
armor4 = $data_armors[@armor4_id]
n += weapon != nil ? weapon.dex_plus : 0
n += armor1 != nil ? armor1.dex_plus : 0
n += armor2 != nil ? armor2.dex_plus : 0
n += armor3 != nil ? armor3.dex_plus : 0
n += armor4 != nil ? armor4.dex_plus : 0
for node in $game_party.nodes
if node.type == 11 and node.learnset[@actor_id]
n += node.value
end
end
return [[n, 1].max, 999].min
end
#--------------------------------------------------------------------------
def base_agi
n = $data_actors[@actor_id].parameters[4, @level]
weapon = $data_weapons[@weapon_id]
armor1 = $data_armors[@armor1_id]
armor2 = $data_armors[@armor2_id]
armor3 = $data_armors[@armor3_id]
armor4 = $data_armors[@armor4_id]
n += weapon != nil ? weapon.agi_plus : 0
n += armor1 != nil ? armor1.agi_plus : 0
n += armor2 != nil ? armor2.agi_plus : 0
n += armor3 != nil ? armor3.agi_plus : 0
n += armor4 != nil ? armor4.agi_plus : 0
for node in $game_party.nodes
if node.type == 12 and node.learnset[@actor_id]
n += node.value
end
end
return [[n, 1].max, 999].min
end
#--------------------------------------------------------------------------
def base_int
n = $data_actors[@actor_id].parameters[5, @level]
weapon = $data_weapons[@weapon_id]
armor1 = $data_armors[@armor1_id]
armor2 = $data_armors[@armor2_id]
armor3 = $data_armors[@armor3_id]
armor4 = $data_armors[@armor4_id]
n += weapon != nil ? weapon.int_plus : 0
n += armor1 != nil ? armor1.int_plus : 0
n += armor2 != nil ? armor2.int_plus : 0
n += armor3 != nil ? armor3.int_plus : 0
n += armor4 != nil ? armor4.int_plus : 0
for node in $game_party.nodes
if node.type == 9 and node.learnset[@actor_id]
n += node.value
end
end
return [[n, 1].max, 999].min
end
#--------------------------------------------------------------------------
def base_atk
weapon = $data_weapons[@weapon_id]
n = weapon != nil ? weapon.atk : 0
for node in $game_party.nodes
if node.type == 14 and node.learnset[@actor_id]
n += node.value
end
end
return [[n, 1].max, 999].min
end
#--------------------------------------------------------------------------
def base_pdef
weapon = $data_weapons[@weapon_id]
armor1 = $data_armors[@armor1_id]
armor2 = $data_armors[@armor2_id]
armor3 = $data_armors[@armor3_id]
armor4 = $data_armors[@armor4_id]
n = weapon != nil ? weapon.pdef : 0
n += armor1 != nil ? armor1.pdef : 0
n += armor2 != nil ? armor2.pdef : 0
n += armor3 != nil ? armor3.pdef : 0
n += armor4 != nil ? armor4.pdef : 0
for node in $game_party.nodes
if node.type == 8 and node.learnset[@actor_id]
n += node.value
end
end
return [[n, 1].max, 999].min
end
#--------------------------------------------------------------------------
def base_mdef
weapon = $data_weapons[@weapon_id]
armor1 = $data_armors[@armor1_id]
armor2 = $data_armors[@armor2_id]
armor3 = $data_armors[@armor3_id]
armor4 = $data_armors[@armor4_id]
n = weapon != nil ? weapon.mdef : 0
n += armor1 != nil ? armor1.mdef : 0
n += armor2 != nil ? armor2.mdef : 0
n += armor3 != nil ? armor3.mdef : 0
n += armor4 != nil ? armor4.mdef : 0
for node in $game_party.nodes
if node.type == 10 and node.learnset[@actor_id]
n += node.value
end
end
return [[n, 1].max, 999].min
end
#--------------------------------------------------------------------------
def base_eva
armor1 = $data_armors[@armor1_id]
armor2 = $data_armors[@armor2_id]
armor3 = $data_armors[@armor3_id]
armor4 = $data_armors[@armor4_id]
n = armor1 != nil ? armor1.eva : 0
n += armor2 != nil ? armor2.eva : 0
n += armor3 != nil ? armor3.eva : 0
n += armor4 != nil ? armor4.eva : 0
for node in $game_party.nodes
if node.type == 13 and node.learnset[@actor_id]
n += node.value
end
end
return [[n, 1].max, 999].min
end
#--------------------------------------------------------------------------
def gain_ap(ap)
@ap= @ap + ap
ap = @ap
l = 0
while(1)
if l*@ap_increase <= @ap_linear
ap-=l*@ap_increase
else
ap-=@ap_linear
end
if ap <= 0
break
end
l+=1
end
@level_max = l
end
#--------------------------------------------------------------------------
def exp=(exp)
gain_ap(exp-@exp)
end
#--------------------------------------------------------------------------
def level
return @level_max - @level_used
end
end
class Game_Party
attr_accessor :nodes
attr_accessor :lines
alias _reinit10 initialize
def initialize
_reinit10
@nodes = RPG::NODES.clone
@lines = RPG::LINES.clone
end
end
class Game_Actors
def [](actor_id)
if actor_id > 999 or $data_actors[actor_id] == nil
return nil
end
if @data[actor_id] == nil
if RPG::ACTORS.has_key?(actor_id)
@data[actor_id] = Tidus.new(actor_id)
else
@data[actor_id] = Game_Actor.new(actor_id)
end
end
return @data[actor_id]
end
end
#--------------------------------------------------------------------------
class Window_Base < Window
def draw_actor_face_grid(actor, x, y)
face = RPG::Cache.picture($data_actors[actor.id].name)
fw = face.width
fh = face.height
src_rect = Rect.new(0, 0, fw, fh)
self.contents.blt(x - fw / 23, y - fh, face, src_rect)
end
end
Here comes the Customization Part (keep it separated from the other scripts):
CODE
module RPG
class Node
attr_reader :id
attr_reader :type
attr_reader :value
attr_reader :x
attr_reader :y
attr_accessor :learnset
#--------------------------------------------------------------------------
def initialize(id,type,value,x,y)
@id = id
@type = type
@value = value
@x = x
@y = y
@learnset = []
end
#--------------------------------------------------------------------------
def morph_into_value(value)
@type = value
if @type == 5 or @type == 6
@value = 20*(2+13*(6-@type))
else
@value = 4
end
if @type == 0
@learnset.clear
end
end
#--------------------------------------
#-----Effects-for-nodes-activations.
#-----Only-skills-need-to-be-actived-here.
#--------------------------------------
def activate(actor_index)
if @learnset[actor_index]
return
end
case @type
when 0
#Empty space
return
when 1
#White Magic
$game_actors[actor_index].learn_skill(@value)
when 2
#Black Magic
$game_actors[actor_index].learn_skill(@value)
when 3
#Skills
$game_actors[actor_index].learn_skill(@value)
when 4
#Specials
$game_actors[actor_index].learn_skill(@value)
when 5..14
#Parameters go here:
# 5 --> HP
# 6 --> MP
# 7 --> Str
# 8 --> Pdef
# 9 --> Int
#10 --> Mdef
#11 --> Dex
#12 --> Agi
#13 --> Eva
#14 --> Atk
else
#Questa รจ la passosfera
@type = 0
return
end
@learnset[actor_index] = true
end
#--------------------------------------------------------------------------
def icon_name(learnt=false)
text = learnt ? "" : "_off"
case @type
when 0
return "Node_void"
when 1
return "Node_white"+ text
when 2
return "Node_black"+ text
when 3
return "Node_skill"+ text
when 4
return "Node_spec"+ text
when 5
return "Node_hp"+ text
when 6
return "Node_mp"+ text
when 7
return "Node_str"+ text
when 8
return "Node_pdef"+ text
when 9
return "Node_mag"+ text
when 10
return "Node_mdef"+ text
when 11
return "Node_acc"+ text
when 12
return "Node_agi"+ text
when 13
return "Node_dex"+ text
when 14
return "Node_luck"+ text
else
return "Node_lvl"+(@type-14).to_s
end
end
end
class Line
attr_reader :id
attr_reader :node1_id
attr_reader :node2_id
attr_reader :type
attr_reader :value
attr_accessor :unlocked
#--------------------------------------------------------------------------
def initialize(id,node1_id,node2_id,type,value = 0)
@unlocked = []
@id = id
@node1_id = node1_id
@node2_id = node2_id
@type = type
@value = value
end
#--------------------------------------------------------------------------
end
#--------CUSTOMIZATION--GOES---HERE!---------------------------------------
#----Actors that use sphere grid:
#---- id => [color_of_the_grid_lines,starting_node]
#--------modify with care, as shown by the line above
ACTORS = {
1 => [Color.new(108, 255, 255, 255),27],
5 => [Color.new(192,255,128,255), 20],
9 => [Color.new(255,192,255,255),67],
10=> [Color.new(128,128,255,255),81]
}
#---effects of the spheres:
#--- do not modify if you use the items I provided!
#----- Just replace IDs in the following vectors:
ITEM_TO_NODES = {
70=> [5,7,8],
71=> [6,9,10],
72=> [11,12,13],
73=> [1,2,3,4],
74=> [14],
75=> [],
76=> [],
77=> [],
78=> [],
79=> [],
80=> [],
81=> [15],
82=> [16],
83=> [17],
84=> [18],
85=> [0],
86=> [0],
87=> [0],
88=> [0],
89=> [0],
90=> [0],
91=> [0],
92=> [0],
93=> [0],
94=> [0],
95=> [5,6,7,8,9,10,11,12,13,14],
96=> [],
97=> [],
98=> [],
99=> []
}
MORPH_INTO = {
85=> 5,
86=> 6,
87=> 7,
88=> 8,
89=> 9,
90=> 10,
91=> 12,
92=> 13,
93=> 11,
94=> 14,
95=> 0
}
COPYSKILLS = {
75=> [5,6,7,8,9,10,11,12,13,14],
76=> [4],
77=> [3],
78=> [1],
79=> [2],
80=> [1,2,3,4,5,6,7,8,9,10,11,12,13,14]
}
BACKWARD = 96
ALLY = 97
ALLYWISE = 98
OMNI = 99
#end of items effect: if you shift the items,
#---- change IDs, from 70->98
#-------to the new IDs in your project.
#----- SPHERE GRID CUSTOMIZATION:
#------ HERE ARE THE LISTS of nodes and lines.
#------- NODES-> (id,type,value,x,y)
#--------place id 1,2,3.. in order or it will NOT work.
#--------Type: goto line 39
#--------Value: what is added to the corresponding parameter
#--------(in case of skill, the ID of the skill)
NODES = [
Node.new(1,3,57,1000,1000),
Node.new(2,0,0,1000,1050),
Node.new(3,0,0,950,1000),
Node.new(4,17,0,1000,950),
Node.new(5,17,0,1050,1000),
Node.new(6,0,0,1100,1000),
Node.new(7,0,0,1150,1000),
Node.new(8,13,2,1070,1070),
Node.new(9,5,200,930,1070),
Node.new(10,14,1,900,1000),
Node.new(11,17,0,1070,930),
Node.new(12,0,0,1000,900),
Node.new(13,17,0,930,930),
Node.new(14,5,200,895,895),
Node.new(15,17,0,1105,895),
Node.new(16,2,9,1000,850),
Node.new(17,6,40,850,1000),
Node.new(18,5,200,895,1105),
Node.new(19,16,0,1000,1150),
Node.new(20,0,0,1105,1105),
Node.new(21,0,0,1205,1105),
Node.new(22,10,2,1250,1000),
Node.new(23,9,2,1350,1050),
Node.new(24,5,200,1420,1120),
Node.new(25,0,0,1370,1120),
Node.new(26,7,3,1320,1120),
Node.new(27,0,0,1385,1085),
Node.new(28,0,0,1455,1085),
Node.new(29,12,4,1455,1155),
Node.new(30,10,2,1420,1170),
Node.new(31,11,3,1420,1220),
Node.new(32,0,0,1490,1190),
Node.new(33,0,0,1520,1120),
Node.new(34,12,2,1350,1190),
Node.new(35,0,0,1490,1050),
Node.new(36,12,4,1200,1190),
Node.new(37,0,0,1560,1050),
Node.new(38,18,0,1610,980),
Node.new(39,4,54,1610,830),
Node.new(40,18,0,1610,880),
Node.new(41,18,0,1560,830),
Node.new(42,18,0,1610,780),
Node.new(43,0,0,1660,830),
Node.new(44,0,0,1760,830),
Node.new(45,0,0,1610,680),
Node.new(46,7,2,1505,725),
Node.new(47,8,2,1460,830),
Node.new(48,0,0,1505,935),
Node.new(49,17,0,1610,730),
Node.new(50,5,200,1680,760),
Node.new(51,6,40,1540,760),
Node.new(52,14,4,1540,900),
Node.new(53,1,1,1680,900),
Node.new(54,0,0,1715,935),
Node.new(55,17,0,1715,1035),
Node.new(56,14,3,1795,1035),
Node.new(57,0,0,1715,1110),
Node.new(58,6,20,1715,1210),
Node.new(59,5,200,1785,1140),
Node.new(60,7,2,1750,1175),
Node.new(61,16,0,1645,1140),
Node.new(62,8,2,1615,1210),
Node.new(63,0,0,1665,1210),
Node.new(64,0,0,1680,1245),
Node.new(65,0,0,1750,1245),
Node.new(66,0,0,1785,1280),
Node.new(67,0,0,1715,1310),
Node.new(68,12,4,1645,1280),
Node.new(69,0,0,1815,1210),
Node.new(70,0,0,1070,1280),
Node.new(71,0,0,950,1280),
Node.new(72,3,61,880,1350),
Node.new(73,5,200,880,1300),
Node.new(74,0,0,880,1250),
Node.new(75,17,0,845,1315),
Node.new(76,14,1,810,1280),
Node.new(77,0,0,780,1350),
Node.new(78,5,200,810,1420),
Node.new(79,8,3,880,1450),
Node.new(80,0,0,950,1420),
Node.new(81,0,0,915,1385),
Node.new(82,7,2,845,1385),
Node.new(83,17,0,930,1350),
Node.new(84,0,0,980,1350),
Node.new(85,9,1,1150,1350),
Node.new(86,8,4,1150,1420),
Node.new(87,7,1,1185,1385),
Node.new(88,10,1,1220,1420),
Node.new(89,14,1,1220,1350),
Node.new(90,6,20,1370,1500),
Node.new(91,6,20,1300,1430),
Node.new(92,0,0,1370,1400),
Node.new(93,18,0,1440,1430),
Node.new(94,4,55,1560,1430),
Node.new(95,13,2,1370,1320),
Node.new(96,5,200,1370,1450),
Node.new(97,0,0,1320,1500),
Node.new(98,11,2,1270,1500),
Node.new(99,6,20,1150,1500),
Node.new(100,11,2,1030,1500),
]
#----Here come the lines
#----LINES -> (id,node1,node2,type(,value))
#----------place id in order or it will NOT work.
#----------Node order is irrelevant.
#--------Types of lines:
#-------0,1 => draws a L shaped line.
#-------2 => draws the straight line.
#-------3,4 => draws an arc beween the nodes
#-------3 => counterclockwise, 4 => clockwise.
#---------The radius of the arc is value (0 is predefinite)
#--------if radius is too short, draws a straight line instead.
LINES = [
Line.new(1,1,2,2),
Line.new(2,2,3,4,50),
Line.new(3,3,4,4,50),
Line.new(4,4,5,4,50),
Line.new(5,5,6,2),
Line.new(6,6,7,2),
Line.new(7,6,8,4,100),
Line.new(8,8,9,4,100),
Line.new(9,9,10,4,100),
Line.new(10,11,12,3,100),
Line.new(11,12,13,3,100),
Line.new(12,7,15,3,150),
Line.new(13,15,11,2),
Line.new(14,16,12,2),
Line.new(15,14,13,2),
Line.new(16,14,17,3,150),
Line.new(17,17,18,3,150),
Line.new(18,18,19,3,150),
Line.new(19,19,20,3,150),
Line.new(20,20,21,2),
Line.new(21,7,22,2),
Line.new(22,22,23,2),
Line.new(23,8,20,2),
Line.new(24,21,26,2),
Line.new(25,26,25,2),
Line.new(26,25,24,2),
Line.new(27,27,24,2),
Line.new(28,27,28,4,50),
Line.new(29,28,29,4,50),
Line.new(30,30,24,2),
Line.new(31,30,31,2),
Line.new(32,31,32,3,100),
Line.new(33,32,33,3,100),
Line.new(34,26,34,3,100),
Line.new(35,34,36,2),
Line.new(36,35,37,2),
Line.new(37,38,37,2),
Line.new(38,39,40,2),
Line.new(39,40,41,4,50),
Line.new(40,41,42,4,50),
Line.new(41,42,43,4,50),
Line.new(42,23,35,4,100),
Line.new(43,43,44,2),
Line.new(44,44,45,3,150),
Line.new(45,45,46,3,150),
Line.new(46,46,47,3,150),
Line.new(47,47,48,3,150),
Line.new(48,48,38,3,150),
Line.new(49,50,49,3,100),
Line.new(50,49,51,3,100),
Line.new(51,51,52,3,100),
Line.new(52,52,53,3,100),
Line.new(53,45,49,2),
Line.new(54,44,54,4,150),
Line.new(55,54,55,2),
Line.new(56,56,55,2),
Line.new(57,57,55,2),
Line.new(58,37,61,2),
Line.new(59,61,58,2),
Line.new(60,60,59,2),
Line.new(61,59,57,3,100),
Line.new(62,57,61,3,100),
Line.new(63,33,62,2),
Line.new(64,62,63,2),
Line.new(65,58,63,2),
Line.new(66,63,64,3,50),
Line.new(67,64,65,3,50),
Line.new(68,65,66,2),
Line.new(69,66,67,4,100),
Line.new(70,67,68,4,100),
Line.new(71,58,69,2),
Line.new(72,36,70,2),
Line.new(73,71,70,2),
Line.new(74,74,73,2),
Line.new(75,73,72,2),
Line.new(76,71,74,3,100),
Line.new(77,76,77,3,100),
Line.new(78,77,78,3,100),
Line.new(79,78,79,3,100),
Line.new(80,79,80,3,100),
Line.new(81,75,72,2),
Line.new(82,75,76,2),
Line.new(83,80,81,2),
Line.new(84,81,82,4,50),
Line.new(85,84,85,2),
Line.new(86,72,83,2),
Line.new(87,84,83,2),
Line.new(88,86,87,2),
Line.new(89,87,88,2),
Line.new(90,85,86,3,50),
Line.new(91,88,89,3,50),
Line.new(92,92,95,2),
Line.new(93,93,94,2),
Line.new(94,91,92,4,100),
Line.new(95,92,93,4,100),
Line.new(96,89,91,2),
Line.new(97,90,96,2),
Line.new(98,80,100,2),
Line.new(99,99,100,2),
Line.new(100,99,98,2),
Line.new(101,97,98,2),
Line.new(102,96,97,3,50),
]
end
Here are some modification scripts:
CODE
class Bitmap
def draw_line(start_x, start_y, end_x, end_y, start_color, width = 1, end_color = start_color)
distance = (start_x - end_x).abs + (start_y - end_y).abs
if end_color == start_color
for i in 1..distance
x = (start_x + 1.0 * (end_x - start_x) * i / distance).to_i
y = (start_y + 1.0 * (end_y - start_y) * i / distance).to_i
if width == 1
self.set_pixel(x, y, start_color)
else
self.fill_rect(x, y, width, width, start_color)
end
end
else
for i in 1..distance
x = (start_x + 1.0 * (end_x - start_x) * i / distance).to_i
y = (start_y + 1.0 * (end_y - start_y) * i / distance).to_i
r = start_color.red * (distance-i)/distance + end_color.red * i/distance
g = start_color.green * (distance-i)/distance + end_color.green * i/distance
b = start_color.blue * (distance-i)/distance + end_color.blue * i/distance
a = start_color.alpha * (distance-i)/distance + end_color.alpha * i/distance
if width == 1
self.set_pixel(x, y, Color.new(r, g, b, a))
else
self.fill_rect(x, y, width, width, Color.new(r, g, b, a))
end
end
end
end
def gradation_rect(x, y, width, height, color1, color2, align = 0)
if align == 0
for i in x...x + width
red = color1.red + (color2.red - color1.red) * (i - x) / (width - 1)
green = color1.green +
(color2.green - color1.green) * (i - x) / (width - 1)
blue = color1.blue +
(color2.blue - color1.blue) * (i - x) / (width - 1)
alpha = color1.alpha +
(color2.alpha - color1.alpha) * (i - x) / (width - 1)
color = Color.new(red, green, blue, alpha)
fill_rect(i, y, 1, height, color)
end
elsif align == 1
for i in y...y + height
red = color1.red +
(color2.red - color1.red) * (i - y) / (height - 1)
green = color1.green +
(color2.green - color1.green) * (i - y) / (height - 1)
blue = color1.blue +
(color2.blue - color1.blue) * (i - y) / (height - 1)
alpha = color1.alpha +
(color2.alpha - color1.alpha) * (i - y) / (height - 1)
color = Color.new(red, green, blue, alpha)
fill_rect(x, i, width, 1, color)
end
elsif align == 2
for i in x...x + width
for j in y...y + height
red = color1.red + (color2.red - color1.red) *
((i - x) / (width - 1.0) + (j - y) / (height - 1.0)) / 2
green = color1.green + (color2.green - color1.green) *
((i - x) / (width - 1.0) + (j - y) / (height - 1.0)) / 2
blue = color1.blue + (color2.blue - color1.blue) *
((i - x) / (width - 1.0) + (j - y) / (height - 1.0)) / 2
alpha = color1.alpha + (color2.alpha - color1.alpha) *
((i - x) / (width - 1.0) + (j - y) / (height - 1.0)) / 2
color = Color.new(red, green, blue, alpha)
set_pixel(i, j, color)
end
end
elsif align == 3
for i in x...x + width
for j in y...y + height
red = color1.red + (color2.red - color1.red) *
((x + width - i) / (width - 1.0) + (j - y) / (height - 1.0)) / 2
green = color1.green + (color2.green - color1.green) *
((x + width - i) / (width - 1.0) + (j - y) / (height - 1.0)) / 2
blue = color1.blue + (color2.blue - color1.blue) *
((x + width - i) / (width - 1.0) + (j - y) / (height - 1.0)) / 2
alpha = color1.alpha + (color2.alpha - color1.alpha) *
((x + width - i) / (width - 1.0) + (j - y) / (height - 1.0)) / 2
color = Color.new(red, green, blue, alpha)
set_pixel(i, j, color)
end
end
end
end
def draw_circle(x,y,radius,width,teta0=0,teta1=2*Math::PI,color=Color.new(0,0,0))
intervals = radius*2*(teta1-teta0).abs#2*Math::PI#16
each = (teta1-teta0).to_f / intervals
for j in 0...width
rad = radius + j - width/2
for i in 0...intervals
angle = (i * each + teta0)#/180 * Math::PI
x_pos = Math.cos(angle) * rad + x
y_pos = -Math.sin(angle) * rad + y
self.fill_rect(x_pos, y_pos, 1,1, color)
end
end
end
end
Here come the windows:
CODE
#--------------------------------------------------------------------------
class Window_SphereGrid_NodesOff < Window_Base
def initialize(actor)
super(0, 0, 3000, 3000)
self.contents = Bitmap.new(width - 32, height - 32)
self.contents.font.name = $fontface
self.contents.font.size = $fontsize
@actor = actor
self.opacity = 0
refresh
end
#--------------------------------------------------------------------------
def refresh
self.contents.clear
for node in $game_party.nodes
draw_node(node)
end
end
#--------------------------------------------------------------------------
def draw_node(node)
bitmap = RPG::Cache.load_bitmap("Graphics/FFX data/",node.icon_name(false),0)
self.contents.blt(node.x, node.y, bitmap, Rect.new(0, 0, 36, 36))
end
end
#--------------------------------------------------------------------------
class Window_SphereGrid_LinesOff < Window_Base
def initialize(actor)
super(0, 0, 3000, 3000)
self.contents = Bitmap.new(width - 32, height - 32)
self.contents.font.name = $fontface
self.contents.font.size = $fontsize
@actor = actor
self.opacity = 0
refresh
end
#--------------------------------------------------------------------------
def refresh
self.contents.clear
for line in $game_party.lines
draw_line(line)
end
end
#--------------------------------------------------------------------------
def draw_line(line)
node1 = $game_party.nodes[line.node1_id-1]
node2 = $game_party.nodes[line.node2_id-1]
x1 = node1.x + 18
y1 = node1.y + 18
x2 = node2.x + 18
y2 = node2.y + 18
deltax = x2 - x1
deltay = y2 - y1
dark = Color.new(50,50,50)
light = Color.new(150,150,150)
v = line.value
make_line(line.type,x1,x2,y1,y2,3,dark,v)
make_line(line.type,x1,x2,y1,y2,1,light,v)
end
#--------------------------------------------------------------------------
def make_line(type,x1,x2,y1,y2,width,color,value = 0)
deltax = x2 - x1
deltay = y2 - y1
a = width/2
case type
when 0
#downward right angle
if deltay >=0
self.contents.draw_line(x1-a, y1-a, x2-a, y1-a, color, width)
self.contents.draw_line(x2-a, y1-a, x2-a, y2-a, color, width)
else
self.contents.draw_line(x1-a, y1-a, x1-a, y2-a, color, width)
self.contents.draw_line(x1-a, y2-a, x2-a, y2-a, color, width)
end
when 1
#upward right angle
if deltay >=0
self.contents.draw_line(x1-a, y1-a, x1-a, y2-a, color, width)
self.contents.draw_line(x1-a, y2-a, x2-a, y2-a, color, width)
else
self.contents.draw_line(x1-a, y1-a, x2-a, y1-a, color, width)
self.contents.draw_line(x2-a, y1-a, x2-a, y2-a, color, width)
end
when 2
#straight line!
self.contents.draw_line(x1-a, y1-a, x2-a, y2-a, color, width)
when 3
#counterclockwise curve line (radius = value)
d = Math.hypot(deltax,deltay)
if 2*value<d
make_line(2,x1,x2,y1,y2,width,color)
return
end
beta = Math.sqrt((value*value).to_f/(d*d)- 0.25)
xc = (x1+x2)/2+beta*deltay
yc = (y1+y2)/2-beta*deltax
angle2 = -Math.atan2(+y2-yc,x2-xc)
angle1 = -Math.atan2(+y1-yc,x1-xc)
if angle2 < angle1
angle2 += 2* Math::PI
end
self.contents.draw_circle(xc,yc,value,width,angle1,angle2,color)
when 4
#clockwise curve line (radius = value)
d = Math.hypot(deltax,deltay)
if 2*value<d
make_line(2,x1,x2,y1,y2,width,color)
return
end
beta = Math.sqrt((value*value).to_f/(d*d)- 0.25)
xc = (x1+x2)/2-beta*deltay
yc = (y1+y2)/2+beta*deltax
angle2 = -Math.atan2(+y2-yc,x2-xc)
angle1 = -Math.atan2(+y1-yc,x1-xc)
if angle2 > angle1
angle2 -= 2* Math::PI
end
self.contents.draw_circle(xc,yc,value,width,angle1,angle2,color)
end
end
end
#--------------------------------------------------------------------------
class Window_SphereGrid_NodesOn < Window_Base
def initialize(actor)
super(0, 0, 3000, 3000)
self.contents = Bitmap.new(width - 32, height - 32)
self.contents.font.name = $fontface
self.contents.font.size = $fontsize
@actor = actor
self.opacity = 0
refresh
end
#--------------------------------------------------------------------------
def refresh(actor = @actor)
@actor = actor
self.contents.clear
for node in $game_party.nodes
draw_node(node)
end
for actor in $game_party.actors
if actor.is_a?(Tidus)
draw_position(actor)
end
end
draw_position(@actor)
end
#--------------------------------------------------------------------------
def draw_position(actor)
node = $game_party.nodes[actor.current_node-1]
dark = Color.new(50,50,50)
self.contents.draw_circle(node.x+18,node.y+18,19,5,0,2*Math::PI,dark)
self.contents.draw_circle(node.x+18,node.y+18,19,3,0,2*Math::PI,actor.grid_color)
end
#--------------------------------------------------------------------------
def draw_node(node)
if !node.learnset[@actor.id]
return
end
bitmap = RPG::Cache.load_bitmap("Graphics/FFX data/",node.icon_name(true),0)
self.contents.blt(node.x, node.y, bitmap, Rect.new(0, 0, 36, 36))
end
#--------------------------------------------------------------------------
def USE_ZERO
curr = @actor.current_node
tie = [curr]
for line in $game_party.lines
if line.node1_id == curr
tie.push(line.node2_id)
end
if line.node2_id == curr
tie.push(line.node1_id)
end
end
return tie
end
#--------------------------------------------------------------------------
end
#--------------------------------------------------------------------------
class Window_SphereGrid_LinesOn < Window_Base
def initialize(actor)
super(0, 0, 3000, 3000)
self.contents = Bitmap.new(width - 32, height - 32)
self.contents.font.name = $fontface
self.contents.font.size = $fontsize
@actor = actor
@TIERS = []
@LINES = []
self.opacity = 0
refresh
end
#--------------------------------------------------------------------------
def refresh(actor = @actor)
@actor = actor
self.contents.clear
for line in $game_party.lines
draw_line(line)
end
# for actor in $game_party.actors
# if actor.is_a?(Tidus)
# draw_position(actor)
# end
# end
# draw_position(@actor)
end
#--------------------------------------------------------------------------
def draw_position(actor)
node = $game_party.nodes[actor.current_node-1]
dark = Color.new(50,50,50)
self.contents.draw_circle(node.x+18,node.y+18,19,5,0,2*Math::PI,dark)
self.contents.draw_circle(node.x+18,node.y+18,19,3,0,2*Math::PI,actor.grid_color)
end
#--------------------------------------------------------------------------
def draw_line(line)
if !line.unlocked[@actor.id]
return
end
node1 = $game_party.nodes[line.node1_id-1]
node2 = $game_party.nodes[line.node2_id-1]
x1 = node1.x + 18
y1 = node1.y + 18
x2 = node2.x + 18
y2 = node2.y + 18
deltax = x2 - x1
deltay = y2 - y1
dark = Color.new(50,50,50)
light = Color.new(150,150,150)
v = line.value
player_color = @actor.grid_color
make_line(line.type,x1,x2,y1,y2,6,dark,v)
make_line(line.type,x1,x2,y1,y2,4,player_color,v)
end
#--------------------------------------------------------------------------
def make_line(type,x1,x2,y1,y2,width,color,value = 0)
deltax = x2 - x1
deltay = y2 - y1
a = width/2
case type
when 0
#downward right angle
if deltay >=0
self.contents.draw_line(x1-a, y1-a, x2-a, y1-a, color, width)
self.contents.draw_line(x2-a, y1-a, x2-a, y2-a, color, width)
else
self.contents.draw_line(x1-a, y1-a, x1-a, y2-a, color, width)
self.contents.draw_line(x1-a, y2-a, x2-a, y2-a, color, width)
end
when 1
#upward right angle
if deltay >=0
self.contents.draw_line(x1-a, y1-a, x1-a, y2-a, color, width)
self.contents.draw_line(x1-a, y2-a, x2-a, y2-a, color, width)
else
self.contents.draw_line(x1-a, y1-a, x2-a, y1-a, color, width)
self.contents.draw_line(x2-a, y1-a, x2-a, y2-a, color, width)
end
when 2
#straight line!
self.contents.draw_line(x1-a, y1-a, x2-a, y2-a, color, width)
when 3
#counterclockwise curve line (radius = value)
d = Math.hypot(deltax,deltay)
if 2*value<d
make_line(2,x1,x2,y1,y2,width,color)
return
end
beta = Math.sqrt((value*value).to_f/(d*d)- 0.25)
xc = (x1+x2)/2+beta*deltay
yc = (y1+y2)/2-beta*deltax
angle2 = -Math.atan2(+y2-yc,x2-xc)
angle1 = -Math.atan2(+y1-yc,x1-xc)
if angle2 < angle1
angle2 += 2* Math::PI
end
self.contents.draw_circle(xc,yc,value,width,angle1,angle2,color)
when 4
#clockwise curve line (radius = value)
d = Math.hypot(deltax,deltay)
if 2*value<d
make_line(2,x1,x2,y1,y2,width,color)
return
end
beta = Math.sqrt((value*value).to_f/(d*d)- 0.25)
xc = (x1+x2)/2-beta*deltay
yc = (y1+y2)/2+beta*deltax
angle2 = -Math.atan2(+y2-yc,x2-xc)
angle1 = -Math.atan2(+y1-yc,x1-xc)
if angle2 > angle1
angle2 -= 2* Math::PI
end
self.contents.draw_circle(xc,yc,value,width,angle1,angle2,color)
end
end
#--------------------------------------------------------------------------
def generate_all(level)
nodelevels = {@actor.current_node => 0}
nodelines = {}
previous_tier = [@actor.current_node]
for j in 0...level
tie = []
for i in 0...previous_tier.size
curr = previous_tier[i]
for line in $game_party.lines
if line.node1_id == curr
unless $game_party.nodes[line.node2_id-1].type > 14
unless nodelevels.has_key?(line.node2_id)
nodelevels[line.node2_id]=j+1
nodelines[line.node2_id]=line.id
tie.push(line.node2_id)
#checking already passed
if line.unlocked[@actor.id]
prev = [line.node2_id]
for k in 0...3
subtie = []
for l in 0...prev.size
kurr = prev[l]
for aline in $game_party.lines
if aline.node1_id == kurr and aline.unlocked[@actor.id]
unless $game_party.nodes[aline.node2_id-1].type > 14
unless nodelevels.has_key?(aline.node2_id)
nodelevels[aline.node2_id]=j+1
nodelines[aline.node2_id]=aline.id
subtie.push(aline.node2_id)
tie.push(aline.node2_id)
next
end
end
end
if aline.node2_id == kurr and aline.unlocked[@actor.id]
unless $game_party.nodes[aline.node1_id-1].type > 14
unless nodelevels.has_key?(aline.node1_id)
nodelevels[aline.node1_id]=j+1
nodelines[aline.node1_id]=aline.id
subtie.push(aline.node1_id)
tie.push(aline.node1_id)
next
end
end
end
end
end
prev = subtie.clone
subtie.clear
end
end
#end checking
end
end
end
if line.node2_id == curr
unless $game_party.nodes[line.node1_id-1].type > 14
unless nodelevels.has_key?(line.node1_id)
nodelevels[line.node1_id]=j+1
nodelines[line.node1_id]=line.id
tie.push(line.node1_id)
#checking already passed
if line.unlocked[@actor.id]
prev = [line.node1_id]
for k in 0...3
subtie = []
for l in 0...prev.size
kurr = prev[l]
for aline in $game_party.lines
if aline.node1_id == kurr and aline.unlocked[@actor.id]
unless $game_party.nodes[aline.node2_id-1].type > 14
unless nodelevels.has_key?(aline.node2_id)
nodelevels[aline.node2_id]=j+1
nodelines[aline.node2_id]=aline.id
subtie.push(aline.node2_id)
tie.push(aline.node2_id)
next
end
end
end
if aline.node2_id == kurr and aline.unlocked[@actor.id]
unless $game_party.nodes[aline.node1_id-1].type > 14
unless nodelevels.has_key?(aline.node1_id)
nodelevels[aline.node1_id]=j+1
nodelines[aline.node1_id]=aline.id
subtie.push(aline.node1_id)
tie.push(aline.node1_id)
next
end
end
end
end
end
prev = subtie.clone
subtie.clear
end
end
#end checking
end
end
end
end
end
previous_tier = tie.clone
tie.clear
end
@nodelevels = nodelevels
@nodelines = nodelines
end
#--------------------------------------------------------------------------
def geodetica(start_id,end_id,level)
id = end_id
lineid = @nodelines[end_id]
path = []
if start_id == end_id
return []
end
loop do
line = $game_party.lines[lineid-1]
if line.node1_id == id
id = line.node2_id
elsif line.node2_id == id
id = line.node1_id
end
path.push(line.id)
if id == start_id
return path
end
lineid = @nodelines[id]
end
end
#--------------------------------------------------------------------------
def nodelevels
return @nodelevels
end
#--------------------------------------------------------------------------
def nodelines
return @nodelines
end
#--------------------------------------------------------------------------
end
#--------------------------------------------------------------------------
class Window_SphereGrid_Mask < Window_Base
def initialize(actor)
super(0, 0, 3000, 3000)
self.contents = Bitmap.new(width - 32, height - 32)
self.contents.font.name = $fontface
self.contents.font.size = $fontsize
@actor = actor
self.opacity = 0
refresh
end
#--------------------------------------------------------------------------
def refresh(actor = @actor)
@actor = actor
self.contents.clear
end
#--------------------------------------------------------------------------
def draw_tier(tier)
for a in tier
node = $game_party.nodes[a-1]
bitmap = RPG::Cache.load_bitmap("Graphics/FFX data/","Cursor_"+@actor.id.to_s,0)
self.contents.blt(node.x-1, node.y-1, bitmap, Rect.new(0, 0, 38, 38),200)
end
end
end
#==============================================================================
# โ Window_Status
#------------------------------------------------------------------------------
# ใในใใผใฟใน็ป้ขใง่กจ็คบใใใใใซไปๆงใฎในใใผใฟในใฆใฃใ
ณใใฆใงใใ
#==============================================================================
class Window_Grid_Stat < Window_Base
#--------------------------------------------------------------------------
# โ ใชใใธใงใฏใๅๆๅ
# actor : ใขใฏใฟใผ
#--------------------------------------------------------------------------
def initialize(actor)
super(0, 64,240, 128)
self.contents = Bitmap.new(width - 32, height - 32)
@actor = actor
self.opacity = 190
refresh
end
#--------------------------------------------------------------------------
# โ ใชใใฌใใทใฅ
#--------------------------------------------------------------------------
def refresh(actor = @actor)
@actor = actor
self.contents.clear
self.contents.font.name = $fontface
self.contents.font.size = $fontsize
draw_actor_face_grid(@actor,0,96)
draw_actor_level(@actor, 120 ,48)
self.contents.font.name = "Monotype Corsiva"
self.contents.font.color = Color.new(180, 255, 6)
self.contents.font.size = $fontsize+4
self.contents.draw_text(120, 16, 200, 32, @actor.name)
end
end
class Window_Spheres < Window_Selectable
#--------------------------------------------------------------------------
# โ ใชใใธใงใฏใๅๆๅ
#--------------------------------------------------------------------------
def initialize(actor)
super(0, 0, 240, 5*32)
@actor = actor
@column_max = 1
refresh
self.index = 0
self.opacity = 190
# ๆฆ้ไธญใฎๅ ดๅใฏใฆใฃใณใใฆใ็ป้ขไธญๅคฎใธ็งปๅใใๅ้ๆใซใ
ใ
end
#--------------------------------------------------------------------------
# โ ใขใคใใ ใฎๅๅพ
#--------------------------------------------------------------------------
def item
return @data[self.index]
end
#--------------------------------------------------------------------------
# โ ใชใใฌใใทใฅ
#--------------------------------------------------------------------------
def refresh(tier = [],actor = @actor)
@actor = actor
@tier = tier
if self.contents != nil
self.contents.dispose
self.contents = nil
end
@data = []
# ใขใคใใ ใ่ฟฝๅ
for i in 1...$data_items.size
if $game_party.item_number(i) > 0 and RPG::ITEM_TO_NODES.has_key?(i)
@data.push($data_items[i])
end
end
# ้
็ฎๆฐใ 0 ใงใชใใใฐใใใใใใใไฝๆใใๅ
จ้
็ฎใๆ็ป
@item_max = @data.size
if @item_max > 0
self.contents = Bitmap.new(width - 32, row_max * 32)
self.contents.font.name = $fontface
self.contents.font.size = $fontsize
for i in 0...@item_max
draw_item(i)
end
end
end
#--------------------------------------------------------------------------
def item_max
return @item_max
end
#--------------------------------------------------------------------------
def activable?(item)
if @tier.size > 0
for i in @tier
if RPG::ITEM_TO_NODES[item.id].include?($game_party.nodes[i-1].type)
unless $game_party.nodes[i-1].learnset[@actor.id]
return true
else
if RPG::MORPH_INTO.has_key?(item.id) and RPG::MORPH_INTO[item.id]==0
return true
end
end
end
end
end
if RPG::COPYSKILLS.has_key?(item.id)
for node in $game_party.nodes
if RPG::COPYSKILLS[item.id].include?(node.type)
if node.learnset[@actor.id]
next
end
for actor in $game_party.actors
if node.learnset[actor.id]
return true
end
end
end
end
end
movespheres = [RPG::BACKWARD,RPG::ALLY,RPG::ALLYWISE,RPG::OMNI]
if movespheres.include?(item.id)
case item.id
when RPG::BACKWARD
for node in $game_party.nodes
if node.learnset[@actor.id]
unless node.id == @actor.current_node
return true
end
end
end
when RPG::ALLY
for actor in $game_party.actors
if actor != @actor and actor.is_a?(Tidus)
return true
end
end
when RPG::ALLYWISE
for actor in $game_party.actors
if actor != @actor and actor.is_a?(Tidus)
for node in $game_party.nodes
if node.learnset[actor.id] and not node.learnset[@actor.id]
return true
end
end
end
end
when RPG::OMNI
for node in $game_party.nodes
unless node.learnset[@actor.id]
unless node.type > 14
return true
end
end
end
end
end
return false
end
#--------------------------------------------------------------------------
def draw_item(index)
item = @data[index]
number = $game_party.item_number(item.id)
if activable?(item)
self.contents.font.color = normal_color
else
self.contents.font.color = disabled_color
end
y = index* 32
rect = Rect.new(x, y, self.width / @column_max - 32, 32)
self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
bitmap = RPG::Cache.icon(item.icon_name)
opacity = self.contents.font.color == normal_color ? 255 : 128
self.contents.blt(0, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)
self.contents.draw_text(20, y, 168, 32, item.name, 0)
self.contents.draw_text(168, y, 16, 32, ":", 1)
self.contents.draw_text(184, y, 24, 32, number.to_s, 2)
end
#--------------------------------------------------------------------------
# โ ใใซใใใญในใๆดๆฐ
#--------------------------------------------------------------------------
def update_help
@help_window.set_text(self.item == nil ? "No item selected." : self.item.description)
end
end
This is the Scene_Sphere_Grid:
CODE
class Scene_Sphere_Grid
#--------------------------------------------------------------------------
# โ ใชใใธใงใฏใๅๆๅ
# actor_index : ใขใฏใฟใผใคใณใใใฏใน
#--------------------------------------------------------------------------
def initialize(actor_index = 0, equip_index = 0)
@actor_index = actor_index
end
#--------------------------------------------------------------------------
# โ ใกใคใณๅฆ็
#--------------------------------------------------------------------------
def main
# ใขใฏใฟใผใๅๅพ
@actor = $game_party.actors[@actor_index]
# ในใใผใฟในใฆใฃใณใใฆใไฝๆ
@grid_nodesoff = Window_SphereGrid_NodesOff.new(@actor)
@grid_nodesoff.z = 50
@grid_linesoff = Window_SphereGrid_LinesOff.new(@actor)
@grid_linesoff.z = 30
@grid_nodeson = Window_SphereGrid_NodesOn.new(@actor)
@grid_nodeson.z = 60
@grid_lineson = Window_SphereGrid_LinesOn.new(@actor)
@grid_lineson.z = 40
@grid_mask = Window_SphereGrid_Mask.new(@actor)
@grid_mask.z = 90
@panorama = Plane.new(Viewport.new(0, 0, 640, 480))
@panorama.bitmap = RPG::Cache.panorama("purple-cosmos",0)
@window = Window_Grid_Stat.new(@actor)
@window.z = 1000
@cursor = Sprite.new
@cursor.bitmap = RPG::Cache.load_bitmap("Graphics/FFX data/","Cursor",0)
@cursor.x = 640/2 - @cursor.bitmap.width/2
@cursor.y = 480/2 - @cursor.bitmap.height/2
@cursor.z = 100
@help = Window_Help.new
@help.opacity = 190
@help.z = 1000
@spheres = Window_Spheres.new(@actor)
@spheres.active = false
@spheres.visible = false
@spheres.y = @window.height+@help.height
@spheres.x = 0
@spheres.z = 1000
@spheres.help_window = @help
@move = Window_Command.new(96,["Move","Use"])
@move.y = @window.height+@spheres.height+@help.height
@move.x = 32
@move.z = 1000
if @actor.level <=0
@move.disable_item(0)
end
@move.visible = false
@move.active = false
@move.opacity = 190
@position = @actor.current_node
@node_free = @position
@index0 = 0
@glow = 0
autoset
tag_set
@fog = Plane.new
@fog.bitmap = Bitmap.new(200,200)
@fog.bitmap.fill_rect(0,0,200,200,Color.new(0,0,0,255))
@fog.opacity = 100
@fog.z = 80
# ใใฉใณใธใทใงใณๅฎ่ก
Graphics.transition
# ใกใคใณใซใผใ
loop do
# ใฒใผใ ็ป้ขใๆดๆฐ
Graphics.update
# ๅ
ฅๅๆ
ๅ ฑใๆดๆฐ
Input.update
# ใใฌใผใ ๆดๆฐ
update
# ็ป้ขใๅใๆฟใใฃใใใซใผใใไธญๆญ
if $scene != self
break
end
end
# ใใฉใณใธใทใงใณๆบๅ
Graphics.freeze
# ใฆใฃใณใใฆใ่งฃๆพ
@grid_nodeson.dispose
@grid_lineson.dispose
@grid_nodesoff.dispose
@grid_linesoff.dispose
@grid_mask.dispose
@panorama.dispose
@cursor.dispose
@window.dispose
@move.dispose
@spheres.dispose
@help.dispose
@fog.dispose
for i in 0...@tags.size
tag = @tags[i]
actor = $game_party.actors[i]
unless actor.is_a?(Tidus)
next
end
tag.dispose
end
end
#--------------------------------------------------------------------------
def autoset(pos = @position)
now = $game_party.nodes[pos-1]
set_grid(-(now.x+34) + 640/2,-(now.y+34) + 480/2)
end
#--------------------------------------------------------------------------
def autoexplore
d = 999999
nodemin = $game_party.nodes[@position-1].id
for node in $game_party.nodes
distance = Math.sqrt((node.x-@nx)*(node.x-@nx)+(node.y-@ny)*(node.y-@ny))
if distance < d
d = distance
nodemin = node.id
end
end
autoset(nodemin)
end
#--------------------------------------------------------------------------
def move_adjacent(direction)
#direction: 0 = up, 1 = right, 2 = down, 3 = left
d = 999999
nodemin = @index0
for node in $game_party.nodes
unless @grid_lineson.nodelevels.has_key?(node.id)
next
end
if node.id == @index0
next
end
delta_x = node.x-@nx
delta_y = node.y-@ny
case direction
when 0
if delta_y >= 0#-delta_x.abs
next
end
when 1
if delta_x <= 0#delta_y.abs
next
end
when 2
if delta_y <= 0#delta_x.abs
next
end
when 3
if delta_x >= 0#-delta_y.abs
next
end
end
distance = Math.sqrt(delta_x*delta_x+delta_y*delta_y)
if distance < d
d = distance
nodemin = node.id
end
end
@index0 = nodemin
autoset(@index0)
end
#--------------------------------------------------------------------------
def use_adjacent(direction)
#direction: 0 = up, 1 = right, 2 = down, 3 = left
d = 999999
nodemin = @index0
for node in $game_party.nodes
unless @use.include?(node.id)
next
end
if node.id == @index0
next
end
delta_x = node.x-@nx
delta_y = node.y-@ny
case direction
when 0
if delta_y >= 0#-delta_x.abs
next
end
when 1
if delta_x <= 0#delta_y.abs
next
end
when 2
if delta_y <= 0#delta_x.abs
next
end
when 3
if delta_x >= 0#-delta_y.abs
next
end
end
distance = Math.sqrt(delta_x*delta_x+delta_y*delta_y)
if distance < d
d = distance
nodemin = node.id
end
end
@index0 = nodemin
autoset(@index0)
end
#--------------------------------------------------------------------------
def update_choose
if Input.trigger?(Input::B)
# ใญใฃใณใปใซ SE ใๆผๅฅ
$game_system.se_play($data_system.cancel_se)
# ใกใใฅใผ็ป้ขใซๅใๆฟใ
@move.active = false
@move.visible = false
# @grid.refresh
return
end
if Input.trigger?(Input::C)
# ใญใฃใณใปใซ SE ใๆผๅฅ
# ใกใใฅใผ็ป้ขใซๅใๆฟใ
case @move.index
when 0
if @actor.level <= 0
$game_system.se_play($data_system.buzzer_se)
return
end
$game_system.se_play($data_system.decision_se)
@move.active = false
@index0 = @actor.current_node
@grid_lineson.generate_all(@actor.level)
@grid_mask.draw_tier(@grid_lineson.nodelevels.keys)
when 1
$game_system.se_play($data_system.decision_se)
@use = @grid_nodeson.USE_ZERO
@spheres.refresh(@use)
@spheres.visible = true
@spheres.active = true
@move.active = false
end
autoset
return
end
end
#--------------------------------------------------------------------------
def update_spheres
if Input.trigger?(Input::B)
# ใญใฃใณใปใซ SE ใๆผๅฅ
$game_system.se_play($data_system.cancel_se)
# ใกใใฅใผ็ป้ขใซๅใๆฟใ
@move.active = true
@spheres.active = false
@spheres.visible = false
return
end
if Input.trigger?(Input::C)
if @spheres.item_max == 0
$game_system.se_play($data_system.buzzer_se)
return
end
generate_usable
if @use == []
$game_system.se_play($data_system.buzzer_se)
return
end
$game_system.se_play($data_system.decision_se)
@spheres.active = false
@spheres.height = 64
@index0 = @use[0]
@grid_mask.draw_tier(@use)
autoset(@index0)
return
end
end
#--------------------------------------------------------------------------
def generate_usable
@use = @grid_nodeson.USE_ZERO
a = @use.clone
for id in @use
if $game_party.nodes[id-1].learnset[@actor.id]
unless RPG::MORPH_INTO.has_key?(@spheres.item.id) and RPG::MORPH_INTO[@spheres.item.id]==0
a.delete(id)
end
end
end
for id in @use
unless RPG::ITEM_TO_NODES[@spheres.item.id].include?($game_party.nodes[id-1].type)
a.delete(id)
end
end
if RPG::COPYSKILLS.has_key?(@spheres.item.id)
for node in $game_party.nodes
if RPG::COPYSKILLS[@spheres.item.id].include?(node.type)
if node.learnset[@actor.id]
next
end
for actor in $game_party.actors
if actor.is_a?(Tidus)
if node.learnset[actor.id]
a.push(node.id)
break
end
end
end
end
end
end
movespheres = [RPG::BACKWARD,RPG::ALLY,RPG::ALLYWISE,RPG::OMNI]
if movespheres.include?(@spheres.item.id)
case @spheres.item.id
when RPG::BACKWARD
for node in $game_party.nodes
if node.learnset[@actor.id]
unless node.id == @actor.current_node
a.push(node.id)
end
end
end
when RPG::ALLY
for actor in $game_party.actors
if actor != @actor and actor.is_a?(Tidus)
a.push(actor.current_node)
end
end
when RPG::ALLYWISE
for actor in $game_party.actors
if actor != @actor and actor.is_a?(Tidus)
for node in $game_party.nodes
if node.learnset[actor.id] and not node.learnset[@actor.id]
a.push(node.id)
end
end
end
end
when RPG::OMNI
for node in $game_party.nodes
unless node.learnset[@actor.id]
unless node.type > 14
a.push(node.id)
end
end
end
end
end
@use = a.clone
end
#--------------------------------------------------------------------------
def update_use
if Input.trigger?(Input::B)
# ใญใฃใณใปใซ SE ใๆผๅฅ
$game_system.se_play($data_system.cancel_se)
# ใกใใฅใผ็ป้ขใซๅใๆฟใ
@use = @grid_nodeson.USE_ZERO
@spheres.refresh(@use)
@spheres.active = true
@spheres.height = 5*32
@grid_mask.refresh
autoset
return
end
if Input.trigger?(Input::UP)
use_adjacent(0)
$game_system.se_play($data_system.cursor_se)
end
if Input.trigger?(Input::RIGHT)
use_adjacent(1)
$game_system.se_play($data_system.cursor_se)
end
if Input.trigger?(Input::DOWN)
use_adjacent(2)
$game_system.se_play($data_system.cursor_se)
end
if Input.trigger?(Input::LEFT)
use_adjacent(3)
$game_system.se_play($data_system.cursor_se)
end
if Input.trigger?(Input::C)
# ใญใฃใณใปใซ SE ใๆผๅฅ
movespheres = [RPG::BACKWARD,RPG::ALLY,RPG::ALLYWISE,RPG::OMNI]
if movespheres.include?(@spheres.item.id)
@actor.current_node = @index0
@position = @actor.current_node
autoset
# @grid_nodeson.refresh
Audio.se_play("Audio/SE/spatial", 100, 100)
else
# ใกใใฅใผ็ป้ขใซๅใๆฟใ
if RPG::MORPH_INTO.include?(@spheres.item.id)
$game_party.nodes[@index0-1].morph_into_value(RPG::MORPH_INTO[@spheres.item.id])
Audio.se_play("Audio/SE/crystal", 100, 100)
# @grid_nodesoff.refresh
else
if $game_party.nodes[@index0-1].type > 14
Audio.se_play("Audio/SE/seaked", 100, 100)
# @grid_nodesoff.refresh
else
Audio.se_play("Audio/SE/Limit-Break", 100, 100)
end
$game_party.nodes[@index0-1].activate(@actor.id)
end
end
@grid_nodesoff.refresh
autoset(@index0)
$game_party.lose_item(@spheres.item.id,1)
@grid_mask.refresh
@grid_nodeson.refresh
@window.refresh
@move.visible = false
@move.active = false
@spheres.visible = false
@spheres.active = false
@spheres.height = 5*32
return
end
end
#--------------------------------------------------------------------------
def update_move
if Input.trigger?(Input::B)
# ใญใฃใณใปใซ SE ใๆผๅฅ
$game_system.se_play($data_system.cancel_se)
# ใกใใฅใผ็ป้ขใซๅใๆฟใ
@move.active = true
@grid_mask.refresh
@window.refresh
autoset
return
end
if Input.trigger?(Input::UP)
move_adjacent(0)
l = @grid_lineson.nodelevels[@index0]
@actor.level_used +=l
@window.refresh
@actor.level_used -=l
$game_system.se_play($data_system.cursor_se)
end
if Input.trigger?(Input::RIGHT)
move_adjacent(1)
l = @grid_lineson.nodelevels[@index0]
@actor.level_used +=l
@window.refresh
@actor.level_used -=l
$game_system.se_play($data_system.cursor_se)
end
if Input.trigger?(Input::DOWN)
move_adjacent(2)
l = @grid_lineson.nodelevels[@index0]
@actor.level_used +=l
@window.refresh
@actor.level_used -=l
$game_system.se_play($data_system.cursor_se)
end
if Input.trigger?(Input::LEFT)
move_adjacent(3)
l = @grid_lineson.nodelevels[@index0]
@actor.level_used +=l
@window.refresh
@actor.level_used -=l
$game_system.se_play($data_system.cursor_se)
end
if Input.trigger?(Input::C)
# ใญใฃใณใปใซ SE ใๆผๅฅ
$game_system.se_play($data_system.decision_se)
# ใกใใฅใผ็ป้ขใซๅใๆฟใ
level = @grid_lineson.nodelevels[@index0]
path = @grid_lineson.geodetica(@actor.current_node,@index0,level)
for line_id in path
$game_party.lines[line_id-1].unlocked[@actor.id]= true
@grid_lineson.draw_line($game_party.lines[line_id-1])
end
@actor.level_used += level
@actor.current_node = @index0
@position = @actor.current_node
autoset
# @grid_lineson.refresh
@grid_nodeson.refresh
@grid_mask.refresh
@window.refresh
if @actor.level <=0
@move.disable_item(0)
end
@move.visible = false
@move.active = false
return
end
end
#--------------------------------------------------------------------------
def update_free_move
a = 10
# B ใใฟใณใๆผใใใๅ ดๅ
if Input.trigger?(Input::B)
# ใญใฃใณใปใซ SE ใๆผๅฅ
$game_system.se_play($data_system.cancel_se)
# ใกใใฅใผ็ป้ขใซๅใๆฟใ
$scene = Scene_Map.new
return
end
if Input.repeat?(Input::DOWN)
set_grid(@grid_nodeson.x,@grid_nodeson.y - a)
return
end
if Input.repeat?(Input::UP)
set_grid(@grid_nodeson.x,@grid_nodeson.y + a)
return
end
if Input.repeat?(Input::LEFT)
set_grid(@grid_nodeson.x + a,@grid_nodeson.y)
return
end
if Input.repeat?(Input::RIGHT)
set_grid(@grid_nodeson.x - a,@grid_nodeson.y)
return
end
unless Input.press?(Input::LEFT) or Input.press?(Input::RIGHT) or Input.press?(Input::UP) or Input.press?(Input::DOWN)
autoexplore
end
if Input.repeat?(Input::R)
$game_system.se_play($data_system.cursor_se)
loop do
@actor_index = (@actor_index+1)% $game_party.actors.size
if @actor_index == @actor.index
break
return
end
if $game_party.actors[@actor_index].is_a?(Tidus)
@actor = $game_party.actors[@actor_index]
@grid_nodeson.refresh(@actor)
@grid_lineson.refresh(@actor)
@grid_mask.refresh(@actor)
@spheres.refresh([],@actor)
@window.refresh(@actor)
@position = @actor.current_node
@move.refresh
if @actor.level <=0
@move.disable_item(0)
end
autoset
break
end
end
return
end
if Input.repeat?(Input::L)
$game_system.se_play($data_system.cursor_se)
loop do
@actor_index = (@actor_index+$game_party.actors.size-1)% $game_party.actors.size
if @actor_index == @actor.index
break
return
end
if $game_party.actors[@actor_index].is_a?(Tidus)
@actor = $game_party.actors[@actor_index]
@grid_nodeson.refresh(@actor)
@grid_lineson.refresh(@actor)
@grid_mask.refresh(@actor)
@spheres.refresh([],@actor)
@window.refresh(@actor)
@position = @actor.current_node
@move.refresh
if @actor.level <=0
@move.disable_item(0)
end
autoset
break
end
end
return
end
if Input.trigger?(Input::C)
# ใญใฃใณใปใซ SE ใๆผๅฅ
$game_system.se_play($data_system.decision_se)
# ใกใใฅใผ็ป้ขใซๅใๆฟใ
autoset
@move.visible = true
@move.active = true
return
end
end
#--------------------------------------------------------------------------
def node_search
for node in $game_party.nodes
if node.x == @nx and node.y == @ny
@node_free = node.id
end
end
end
#--------------------------------------------------------------------------
def set_grid(x,y)
@grid_nodeson.x = x
@grid_nodeson.y = y
@grid_lineson.x = x
@grid_lineson.y = y
@grid_nodesoff.x = x
@grid_nodesoff.y = y
@grid_linesoff.x = x
@grid_linesoff.y = y
@grid_mask.x = x
@grid_mask.y = y
end
#--------------------------------------------------------------------------
def tag_set
@tags = []
for i in 0...$game_party.actors.size
actor = $game_party.actors[i]
unless actor.is_a?(Tidus)
next
end
@tags[i] = Sprite.new
bit = RPG::Cache.load_bitmap("Graphics/FFX data/","blued",0)
@tags[i].bitmap = bit.clone
@tags[i].bitmap.font.size = $fontsize-4
@tags[i].bitmap.font.name = "Times New Roman"
@tags[i].bitmap.font.color = Color.new(255,255,255,255)
@tags[i].bitmap.draw_text(10,-4,100,32,actor.name,0)
node = $game_party.nodes[actor.current_node-1]
@tags[i].x = @grid_nodeson.x + node.x - @tags[i].bitmap.width + 18
@tags[i].y = @grid_nodeson.y + node.y
@tags[i].z = 500
end
end
#--------------------------------------------------------------------------
def text_set
if @move.active
case @move.index
when 0
@help.set_text("Moves the hero upon the grid.",1)
when 1
@help.set_text("Activates a sphere on the grid.",1)
end
return
end
if @spheres.active
return
end
txt = ["","white magic","black magic","skill","special",
$data_system.words.hp,$data_system.words.sp,
$data_system.words.str,$data_system.words.pdef,
$data_system.words.int,$data_system.words.mdef,
$data_system.words.dex,$data_system.words.agi,
"Evasion",$data_system.words.atk]
nod = $game_party.nodes[@node_free-1]
case nod.type
when 0
@help.set_text("Empty Node.",1)
when 1..4
@help.set_text("Learns the "+txt[nod.type]+" "+$data_skills[nod.value].name+".",1)
when 5..14
@help.set_text("Increases "+txt[nod.type]+" by " +nod.value.to_s+" points.",1)
when 15..18
@help.set_text("Block level " +(nod.type-14).to_s+".",1)
end
end
#--------------------------------------------------------------------------
def tag_update
timez = []
tagz = []
for i in 0...@tags.size
tag = @tags[i]
actor = $game_party.actors[i]
unless actor.is_a?(Tidus)
next
end
node = $game_party.nodes[$game_party.actors[i].current_node-1]
if tagz.include?($game_party.actors[i].current_node)
timez[tagz.index($game_party.actors[i].current_node)] += 1
else
tagz.push($game_party.actors[i].current_node)
timez.push(0)
end
wid = @tags[i].bitmap.width
ind = timez[tagz.index($game_party.actors[i].current_node)]
tag.x = @grid_nodeson.x + node.x - wid + 18 + (wid+30)*(ind%2)
tag.y = @grid_nodeson.y + node.y + 40*(ind/2)
end
end
#--------------------------------------------------------------------------
def update
# @grid.update
# @window.update
@move.update
@spheres.update
@panorama.ox += 1
@panorama.oy += 1
# @panorama.ox = -@grid.x
# @panorama.oy = -@grid.y
@nx = 320-@grid_nodeson.x - 34
@ny = 240-@grid_nodeson.y - 34
@cursor.bitmap = RPG::Cache.load_bitmap("Graphics/FFX data/","Cursor",@glow)
@glow = (10 + @glow)%360
node_search
text_set
#update different scenes:
if @move.active and @move.visible
update_choose
return
end
if @move.visible and !@move.active and !@spheres.visible
update_move
tag_update
return
end
if @spheres.active and @spheres.visible
update_spheres
return
end
if !@spheres.active and @spheres.visible
update_use
tag_update
return
end
if !@move.visible
update_free_move
tag_update
return
end
end
#--------------------------------------------------------------------------
end
End of the script pages

[/spoiler]
CustomizationThis script has many levels of customisation:
1- You just adapt the script to your game: Modify the Hash ACTORS, adding the actors as you like.
2-If you wish to move items in the database (mine is 70->98) modify ALL the vectors, hashes etc below ACTORS:
just replace the ids with the ones in your project (it is easier to do it than to explain it)
3-You wish to modify the sphere grid (as expected, since every game should have its own).
in this case, you have to modify the NODES and LINES vectors, replace the existing ones with your own creations!
how to do this is explained inside the script.
4-You also wish to modify the effect of the items, or add new types of nodes on the grid.
This is rather difficult and I suppose you should ask me in order to know if what you wish to add is possible.
In any case, you can just pm me to ask for help.
Compatibility This should be compatible with any battle system you use.
Screenshot [spoiler="Screenshots"]


[/spoiler]
DEMO Sphere Grid DemoInstallation You can copy the scripts from above, or from the demo, it is the same. Just make sure to have all the graphics files:
FFX Data folder in your project. (you might have to modify the Cursor_n files: you have to add one for each character that uses the grid.
You also need to color them in order to match the color you entered in the ACTORS hash (ask me if you need help).
6 icon files: they are the spheres icons.
purple-cosmos.jpg: It is the background of the grid.
Pictures: Make sure this folder contains the faces of your characters with their respective names.
this is it.
Terms and Conditions Feel free to use it but do not claim it as your own.
CreditsI have copied the draw_line method but do not remember where it came from... if you can find it I will add the author to the credits. Everything else has been written by me.