local SIN_60 = 0.866
local CENTER_TO_CORNER = 0.58
--Math Functions for Triangle Select
local function cap(val, min_val, max_val)
if val < min_val then
return min_val
elseif val > max_val then
return max_val
end
return val
end
-- calculate the magnitude of a line
local function magnitude(startx,starty,endx,endy)
local x = endx - startx
local y = endy - starty
return sqrt( x * x + y * y )
end
-- Inherited from Vdo_base_object
Vdo_triangle_select = Vdo_base_object:new_base()
local TRIANGLE_NW_X = 32
local TRIANGLE_NW_Y = 32
local TRIANGLE_SIDE = 235
local Min_x = 0
local Min_y = 0
local Max_x = TRIANGLE_SIDE
-- height of triangle
local Max_y = TRIANGLE_SIDE * SIN_60
local Fat_txt
local Skinny_txt
local Strength_txt
local Cursor
local function update_percent_fields(fat, skinny, strength)
-- update % displays
local body
local insert_values = { [0] = fat }
body = vint_insert_values_in_string("STORE_FAT", insert_values)
Fat_txt:set_text(body)
insert_values = { [0] = skinny }
body = vint_insert_values_in_string("STORE_SKINNY", insert_values)
Skinny_txt:set_text(body)
insert_values = { [0] = strength }
body = vint_insert_values_in_string("STORE_STRENGTH", insert_values)
Strength_txt:set_text(body)
end
function Vdo_triangle_select:init()
self.btn_select = Vdo_button_toggle:new("btn_select", self.handle, self.doc_handle)
self.btn_highlight = Vdo_button_highlight:new("btn_highlight", self.handle, self.doc_handle)
self.btn_highlight:show_button(CTRL_MENU_BUTTON_A)
self.btn_select:set_label("STORE_SELECT_BUILD")
self.tri_color_grp = Vdo_base_object:new("tri_color_grp", self.handle, self.doc_handle)
self.tri_color_grp:set_visible(false)
self.btn_select:set_highlight(true)
self.btn_highlight:set_highlight(true)
self.pulse_anim = Vdo_anim_object:new("stick_pulse_anim", self.handle, self.doc_handle)
self.pulse_anim:unpause()
-- Temp: bitmap doesn't line up with triangle edges
-- TRIANGLE_NW_X, TRIANGLE_NW_Y = triangle_h:get_anchor()
--Get Cursor Handle
Cursor = Vdo_base_object:new("cursor", self.handle, self.doc_handle)
local triangle_bmp = Vdo_base_object:new("triangle_base", self.handle, self.doc_handle)
triangle_bmp:set_image("ui_menu_pcr_tri")
--Modify Stick Graphic depending on system
local cursor_bmp = Vdo_base_object:new("stick_bitmap", Cursor.handle, Cursor.doc_handle)
local cursor_txt = Vdo_base_object:new("stick_text", Cursor.handle, Cursor.doc_handle)
self.glow_bmp = Vdo_base_object:new("glow", Cursor.handle, Cursor.doc_handle)
if game_get_platform() == "PS3" then
cursor_bmp:set_image("ui_hud_combo_thumb_ps3")
cursor_txt:set_text("L")
elseif (game_get_platform() == "PC") then
cursor_bmp:set_image("ui_pc_body_select_circle")
cursor_txt:set_visible(false)
else
cursor_bmp:set_image("ui_hud_combo_thumb")
cursor_txt:set_text("LS")
end
--Uncomment these for more accurate cursor
--cursor_bmp:set_visible(false)
--cursor_txt:set_visible(false)
--self.glow_bmp:set_visible(false)
-- start in the middle of the triangle - need to update based on current settings
Cursor:set_anchor(TRIANGLE_NW_X + Max_x / 2, TRIANGLE_NW_Y + TRIANGLE_SIDE * CENTER_TO_CORNER)
Fat_txt = Vdo_base_object:new("fat_txt", self.handle, self.doc_handle)
Skinny_txt = Vdo_base_object:new("skinny_txt", self.handle, self.doc_handle)
Strength_txt = Vdo_base_object:new("strength_txt", self.handle, self.doc_handle)
update_percent_fields(0, 0, 0)
end
function Vdo_triangle_select:init_morphs(str, skin, fat, x, y)
-- leave cursor in middle for never initialized position
if x >= 0 and y >= 0 then
Cursor:set_anchor(x,y)
else
Cursor:set_anchor(TRIANGLE_NW_X + Max_x / 2, TRIANGLE_NW_Y + TRIANGLE_SIDE * CENTER_TO_CORNER)
end
-- update % displays
update_percent_fields(floor(fat * 100 + 0.5), floor(skin * 100 + 0.5), floor(str * 100 + 0.5))
end
-- Move the left stick by the given magnitudes
function Vdo_triangle_select:move_left_stick(mag_x, mag_y)
local cursor_x, cursor_y = Cursor:get_anchor()
local new_x = cursor_x + mag_x
local new_y = cursor_y - mag_y
-- convert from screen position
local rel_x = new_x - TRIANGLE_NW_X
local rel_y = new_y - TRIANGLE_NW_Y
local ax = 0
local ay = Max_y
local bx = (Max_x / 2)
local by = 0
local cx = Max_x
local cy = ay
-- Check the location of the mouse cursor against each side of the triangle
-- If the point is "inside," it is to the right or on the line
local point_inside_left = false
local point_inside_right = false
local point_inside_bottom = false
if which_side_of_2d_line(rel_x, rel_y, ax, ay, bx, by) >= 0 then
point_inside_left = true
end
if which_side_of_2d_line(rel_x, rel_y, bx, by, cx, cy) >= 0 then
point_inside_right = true
end
if which_side_of_2d_line(rel_x, rel_y, cx, cy, ax, ay) >= 0 then
point_inside_bottom = true
end
local new_x, new_y
--local rel_x, rel_y
if point_inside_left and point_inside_right and point_inside_bottom then
-- If the point is inside the triangle, then done
else
-- If the point is not on the inside of the triangle, find the closest point on the
-- line that the point is not on the inside of.
if not point_inside_left then
rel_x, rel_y= closest_point_on_line_segment(rel_x, rel_y, ax, ay, bx, by)
end
if not point_inside_right then
rel_x, rel_y = closest_point_on_line_segment(rel_x, rel_y, bx, by, cx, cy)
end
if not point_inside_bottom then
rel_x, rel_y = closest_point_on_line_segment(rel_x, rel_y, cx, cy, ax, ay)
end
end
-- convert from screen coord (top is lower y value) to Cartesian for my sanity
rel_y = Max_y - rel_y
-- Get percentages for display, and to update the morph.
local center_x = 117.5
local center_y = 67.84
local d_left_corner = magnitude(0, 0, rel_x, rel_y)
local d_right_corner = magnitude(rel_x, rel_y, Max_x, 0)
local d_top_corner = magnitude(rel_x, rel_y, Max_x / 2, Max_y)
local d_bottom = d_left_corner + d_right_corner
local d_left = d_left_corner + d_top_corner
local d_right = d_right_corner + d_top_corner
local closest
if d_bottom < d_left then
if d_bottom < d_right then
-- closest to bottom
closest = 1
else
-- closest to right
closest = 0
end
else
if d_left < d_right then
-- closest to left
closest = 2
else
-- closest to right
closest = 0
end
end
local d_center = magnitude(center_x, center_y, rel_x, rel_y)
local d_min = magnitude(center_x, center_y, 0, 0) * 2
local d_max = Max_x * 2 --magnitude(0, 0, Max_x, 0);
local fat_percent = d_min
local skinny_percent = d_min
local muscle_percent = d_min
-- left side (fat)
if closest ~= 2 then
if d_right < d_bottom then
-- right section
if d_right_corner > d_top_corner then
fat_percent = magnitude(0, 0, center_x, center_y) + magnitude(center_x, center_y, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x / 2, Max_y)
else
fat_percent = magnitude(0, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x / 2, Max_y)
end
else
-- bottom section
if d_right_corner > d_left_corner then
fat_percent = magnitude(0, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, center_x, center_y) + magnitude(center_x, center_y, Max_x /2, Max_y)
else
fat_percent = magnitude(0, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x / 2, Max_y)
end
end
end
fat_percent = (fat_percent - d_min) / (d_max - d_min)
-- right side (skinny)
if closest ~= 0 then
if d_left < d_bottom then
-- left section
if d_left_corner > d_top_corner then
skinny_percent = magnitude(Max_x, 0, center_x, center_y) + magnitude(center_x, center_y, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x / 2, Max_y)
else
skinny_percent = magnitude(Max_x, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x / 2, Max_y)
end
else
-- bottom section
if d_left_corner > d_right_corner then
skinny_percent = magnitude(Max_x, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, center_x, center_y) + magnitude(center_x, center_y, Max_x /2, Max_y)
else
skinny_percent = magnitude(Max_x, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x / 2, Max_y)
end
end
end
skinny_percent = (skinny_percent - d_min) / (d_max - d_min)
-- bottom side (strength)
if closest ~= 1 then
if d_left < d_right then
-- left section
if d_top_corner > d_left_corner then
muscle_percent = magnitude(0, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, center_x, center_y) + magnitude(center_x, center_y, Max_x, 0)
else
muscle_percent = magnitude(0, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x, 0)
end
else
-- right section
if d_top_corner > d_right_corner then
muscle_percent = magnitude(0, 0, center_x, center_y) + magnitude(center_x, center_y, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x, 0)
else
muscle_percent = magnitude(0, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x, 0)
end
end
end
muscle_percent = (muscle_percent - d_min) / (d_max - d_min)
-- update % displays
update_percent_fields(floor(fat_percent * 100 + 0.5), floor(skinny_percent * 100 + 0.5), floor(muscle_percent * 100 + 0.5))
-- convert back to screen coord
rel_y = Max_y - rel_y
-- convert back to screen position
new_x = rel_x + TRIANGLE_NW_X
new_y = rel_y + TRIANGLE_NW_Y
Cursor:set_anchor(new_x, new_y)
if new_x ~= self.old_x or new_y ~= self.old_y then
game_UI_audio_play("UI_Cell_Nav")
end
self.old_x = new_x
self.old_y = new_y
return muscle_percent, skinny_percent, fat_percent, new_x, new_y
end
function Vdo_triangle_select:set_highlight_color(new_color)
self.btn_highlight:set_highlight_color(new_color)
Fat_txt:set_color(new_color.R, new_color.G, new_color.B)
Skinny_txt:set_color(new_color.R, new_color.G, new_color.B)
Strength_txt:set_color(new_color.R, new_color.G, new_color.B)
self.glow_bmp:set_color(new_color.R, new_color.G, new_color.B)
self.tri_color_grp:set_color(new_color.R, new_color.G, new_color.B)
self.tri_color_grp:set_visible(true)
end
-- =====================================
-- Mouse Specific Functions
-- =====================================
function Vdo_triangle_select:update_mouse(mouse_x, mouse_y)
if (mouse_x ~= nil) and (mouse_y ~= nil) then
local triangle_base = Vdo_base_object:new("triangle_base", self.handle, self.doc_handle)
local tri_x, tri_y = vint_get_global_anchor(triangle_base.handle, self.doc_handle)
local tri_width, tri_height = triangle_base:get_actual_size()
-- Calculate the points of the innermost triangle (A, B, C) in screen space
-- A is the bottom left point, B is the top point, C is the bottom right point
local ax = tri_x + TRIANGLE_NW_X
local ay = tri_y + TRIANGLE_NW_Y + Max_y + 4
local bx = tri_x + (tri_width / 2)
local by = tri_y + TRIANGLE_NW_Y + 4
local cx = tri_x + tri_width - TRIANGLE_NW_X
local cy = ay
-- Adjust the mouse_x and mouse_y position based on the resolution/etc
local screen_w, screen_h = vint_get_screen_size()
local anchor_x, anchor_y
local relative_x, relative_y
if vint_is_std_res() then
local doc_width = screen_h * 4 / 3
local offset = (doc_width - screen_w) / 2
mouse_x = ((mouse_x + offset) * 640 / doc_width)
mouse_y = mouse_y * 480 / screen_h
mouse_x = tri_x + (mouse_x - tri_x) * 1.5
mouse_y = tri_y + (mouse_y - tri_y) * 1.5
else
local doc_width = screen_h * 16 / 9
local offset = (doc_width - screen_w) / 2
mouse_x = ((mouse_x + offset) * 1280 / doc_width)
mouse_y = mouse_y * 720 / screen_h
end
-- Check the location of the mouse cursor against each side of the triangle
-- If the point is "inside," it is to the right or on the line
local point_inside_left = false
local point_inside_right = false
local point_inside_bottom = false
if which_side_of_2d_line(mouse_x, mouse_y, ax, ay, bx, by) >= 0 then
point_inside_left = true
end
if which_side_of_2d_line(mouse_x, mouse_y, bx, by, cx, cy) >= 0 then
point_inside_right = true
end
if which_side_of_2d_line(mouse_x, mouse_y, cx, cy, ax, ay) >= 0 then
point_inside_bottom = true
end
local new_x, new_y
local rel_x, rel_y
if point_inside_left and point_inside_right and point_inside_bottom then
-- If the point is inside the triangle, calculate the position of the mouse in the triangle space
new_x = mouse_x - tri_x
new_y = mouse_y - tri_y - 4
else
-- If the point is not on the inside of the triangle, find the closest point on the
-- line that the point is not on the inside of.
if not point_inside_left then
new_x, new_y = closest_point_on_line_segment(mouse_x, mouse_y, ax, ay, bx, by)
end
if not point_inside_right then
new_x, new_y = closest_point_on_line_segment(mouse_x, mouse_y, bx, by, cx, cy)
end
if not point_inside_bottom then
new_x, new_y = closest_point_on_line_segment(mouse_x, mouse_y, cx, cy, ax, ay)
end
-- Calculate the position of the point in the triangle space
new_x = new_x - tri_x
new_y = new_y - tri_y - 4
end
rel_x = new_x - TRIANGLE_NW_X
rel_y = Max_y - (new_y - TRIANGLE_NW_Y)
Cursor:set_anchor(new_x, new_y)
-- Cap just in case.
rel_x = cap(rel_x, 0, Max_x)
rel_y = cap(rel_y, 0, Max_y)
local center_x = 117.5
local center_y = 67.84
local d_left_corner = magnitude(0, 0, rel_x, rel_y)
local d_right_corner = magnitude(rel_x, rel_y, Max_x, 0)
local d_top_corner = magnitude(rel_x, rel_y, Max_x / 2, Max_y)
local d_bottom = d_left_corner + d_right_corner
local d_left = d_left_corner + d_top_corner
local d_right = d_right_corner + d_top_corner
local closest
if d_bottom < d_left then
if d_bottom < d_right then
-- closest to bottom
closest = 1
else
-- closest to right
closest = 0
end
else
if d_left < d_right then
-- closest to left
closest = 2
else
-- closest to right
closest = 0
end
end
local d_center = magnitude(center_x, center_y, rel_x, rel_y)
local d_min = magnitude(center_x, center_y, 0, 0) * 2
local d_max = Max_x * 2 --magnitude(0, 0, Max_x, 0);
local fat_percent = d_min
local skinny_percent = d_min
local muscle_percent = d_min
-- left side (fat)
if closest ~= 2 then
if d_right < d_bottom then
-- right section
if d_right_corner > d_top_corner then
fat_percent = magnitude(0, 0, center_x, center_y) + magnitude(center_x, center_y, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x / 2, Max_y)
else
fat_percent = magnitude(0, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x / 2, Max_y)
end
else
-- bottom section
if d_right_corner > d_left_corner then
fat_percent = magnitude(0, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, center_x, center_y) + magnitude(center_x, center_y, Max_x /2, Max_y)
else
fat_percent = magnitude(0, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x / 2, Max_y)
end
end
end
fat_percent = (fat_percent - d_min) / (d_max - d_min)
-- right side (skinny)
if closest ~= 0 then
if d_left < d_bottom then
-- left section
if d_left_corner > d_top_corner then
skinny_percent = magnitude(Max_x, 0, center_x, center_y) + magnitude(center_x, center_y, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x / 2, Max_y)
else
skinny_percent = magnitude(Max_x, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x / 2, Max_y)
end
else
-- bottom section
if d_left_corner > d_right_corner then
skinny_percent = magnitude(Max_x, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, center_x, center_y) + magnitude(center_x, center_y, Max_x /2, Max_y)
else
skinny_percent = magnitude(Max_x, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x / 2, Max_y)
end
end
end
skinny_percent = (skinny_percent - d_min) / (d_max - d_min)
-- bottom side (strength)
if closest ~= 1 then
if d_left < d_right then
-- left section
if d_top_corner > d_left_corner then
muscle_percent = magnitude(0, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, center_x, center_y) + magnitude(center_x, center_y, Max_x, 0)
else
muscle_percent = magnitude(0, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x, 0)
end
else
-- right section
if d_top_corner > d_right_corner then
muscle_percent = magnitude(0, 0, center_x, center_y) + magnitude(center_x, center_y, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x, 0)
else
muscle_percent = magnitude(0, 0, rel_x, rel_y) + magnitude(rel_x, rel_y, Max_x, 0)
end
end
end
muscle_percent = (muscle_percent - d_min) / (d_max - d_min)
-- update % displays
update_percent_fields(floor(fat_percent * 100 + 0.5), floor(skinny_percent * 100 + 0.5), floor(muscle_percent * 100 + 0.5))
return muscle_percent, skinny_percent, fat_percent, new_x, new_y
end
end