ff_effect.lua (3635B)
1 local base = string.match(..., "(.-)[^%.]+%.[^%.]+$") 2 local enums = require(base.."ev_api.decls").enums 3 local eh = require(base.."helper.enum") 4 local ffi = require("ffi") 5 local fh = require(base.."helper.ffi_struct") 6 7 local ff_trigger = require(base.."ev_api.ff_trigger").new 8 local ff_replay = require(base.."ev_api.ff_replay").new 9 10 local ff_constant_effect = require(base.."ev_api.ff_constant_effect").new 11 local ff_ramp_effect = require(base.."ev_api.ff_ramp_effect").new 12 local ff_condition_effect = require(base.."ev_api.ff_condition_effect").new 13 local ff_periodic_effect = require(base.."ev_api.ff_periodic_effect").new 14 local ff_rumble_effect = require(base.."ev_api.ff_rumble_effect").new 15 16 local format = string.format 17 18 local mt, index = {}, {} 19 20 -- COMMON CRAP 21 local FF_EFFECT = eh.filter_min_max( 22 enums.FF, enums.FF.EFFECT_MIN, enums.FF.EFFECT_MAX) 23 index.FF_EFFECT = FF_EFFECT 24 fh.gen_enum_accessor(index, FF_EFFECT, "type") 25 fh.gen_raw_accessor(index, "id") 26 27 local DIRECTION = eh.make_enum{ 28 {"DOWN", 0}, {"LEFT", 0x4000}, {"UP", 0x8000}, {"RIGHT", 0xc000}, 29 } 30 index.DIRECTION = DIRECTION 31 fh.gen_enum_accessor(index, DIRECTION, "direction") 32 33 fh.gen_wrap_accessor(index, "trigger", ff_trigger) 34 fh.gen_wrap_accessor(index, "replay", ff_replay) 35 36 -- UNION MAGIC 37 local function check_union(self, name, exp_type) 38 if self.raw.type ~= exp_type then 39 error("Wrong enum variant "..self.type.." while getting "..name) 40 end 41 end 42 43 local function typechecked_acc(name, exp_type, wrap) 44 index["get_"..name] = function(self) 45 check_union(self, name, exp_type) 46 return wrap(self.raw.u[name]) 47 end 48 index["set_"..name] = function(self, ...) 49 check_union(self, name, exp_type) 50 self.raw.u[name] = wrap(...).raw 51 end 52 end 53 54 typechecked_acc("constant", FF_EFFECT.CONSTANT, ff_constant_effect) 55 typechecked_acc("ramp", FF_EFFECT.RAMP, ff_ramp_effect) 56 typechecked_acc("periodic", FF_EFFECT.PERIODIC, ff_periodic_effect) 57 58 local valid_conditions = { 59 [FF_EFFECT.SPRING] = true, [FF_EFFECT.FRICTION] = true, 60 [FF_EFFECT.DAMPER] = true, [FF_EFFECT.INERTIA] = true, 61 } 62 for i=0,1 do 63 name = "condition"..i 64 index["get_"..name] = function(self) 65 if not valid_conditions[self.raw.type] then 66 error("Wrong enum variant "..self.type.." while getting "..name) 67 end 68 return ff_condition_effect(self.raw.u.condition[i]) 69 end 70 index["set_"..name] = function(self, ...) 71 if not valid_conditions[self.raw.type] then 72 error("Wrong enum variant "..self.type.." while getting "..name) 73 end 74 self.raw.u.condition[i] = ff_condition_effect(...).raw 75 end 76 end 77 78 typechecked_acc("rumble", FF_EFFECT.RUMBLE, ff_rumble_effect) 79 80 -- MISC 81 -- hack: we need to set type before setting code 82 local orig_set = fh.base_funcs.set_from_table 83 function index:set_from_table(tbl) 84 if tbl.type then self.type = tbl.type end 85 orig_set(self, tbl) 86 end 87 88 function index:tostring() 89 local t, subs = self.type, "" 90 if t == "CONSTANT" then subs = ", constant="..self.constant:tostring() 91 elseif t == "RAMP" then subs = ", ramp="..self.ramp:tostring() 92 elseif t == "PERIODIC" then subs = ", periodic="..self.periodic:tostring() 93 elseif t == "SPRING" or t == "FRICTION" or t == "DAMPER" or t == "INERTIA" then 94 subs = format(", condition0=%s, condition1=%s", 95 self.condition0, self.condition1) 96 elseif t == "RUMBLE" then subs = ", rumble="..self.rumble:tostring() end 97 98 return format( 99 "ff_effect{type=%s, id=%d, direction=%s, trigger=%s, replay=%s%s}", 100 self.type, self.id, self.direction, self.trigger, self.replay, subs) 101 end 102 mt.__tostring = index.tostring 103 104 return fh.base(mt, index, ffi.typeof("struct ff_effect"))