123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
- // Copyright (C) 2015 Faust Logic, Inc.
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- #include "afx/arcaneFX.h"
- #include "console/engineAPI.h"
- #include "afx/afxEffectWrapper.h"
- #include "afx/ce/afxPhraseEffect.h"
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // afxPhraseEffectData::ewValidator
- //
- // When an effect is added using "addEffect", this validator intercepts the value
- // and adds it to the dynamic effects list.
- //
- void afxPhraseEffectData::ewValidator::validateType(SimObject* object, void* typePtr)
- {
- afxPhraseEffectData* eff_data = dynamic_cast<afxPhraseEffectData*>(object);
- afxEffectBaseData** ew = (afxEffectBaseData**)(typePtr);
- if (eff_data && ew)
- {
- eff_data->fx_list.push_back(*ew);
- *ew = 0;
- }
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
- // afxPhraseEffectData
- IMPLEMENT_CO_DATABLOCK_V1(afxPhraseEffectData);
- ConsoleDocClass( afxPhraseEffectData,
- "@brief A datablock that specifies a Phrase Effect, a grouping of other effects.\n\n"
- "A Phrase Effect is a grouping or phrase of effects that do nothing until certain trigger events occur. It's like having a whole "
- "Effectron organized as an individual effect."
- "\n\n"
- "Phrase effects can respond to a number of different kinds of triggers:\n"
- " -- Player triggers such as footsteps, jumps, landings, and idle triggers.\n"
- " -- Arbitrary animation triggers on dts-based scene objects.\n"
- " -- Arbitrary trigger bits assigned to active choreographer objects."
- "\n\n"
- "@ingroup afxEffects\n"
- "@ingroup AFX\n"
- "@ingroup Datablocks\n"
- );
- afxPhraseEffectData::afxPhraseEffectData()
- {
- duration = 0.0f;
- n_loops = 1;
- // dummy entry holds effect-wrapper pointer while a special validator
- // grabs it and adds it to an appropriate effects list
- dummy_fx_entry = NULL;
- // marked true if datablock ids need to
- // be converted into pointers
- do_id_convert = false;
- trigger_mask = 0;
- match_type = MATCH_ANY;
- match_state = STATE_ON;
- phrase_type = PHRASE_TRIGGERED;
- no_choreographer_trigs = false;
- no_cons_trigs = false;
- no_player_trigs = false;
- on_trig_cmd = ST_NULLSTRING;
- }
- afxPhraseEffectData::afxPhraseEffectData(const afxPhraseEffectData& other, bool temp_clone) : GameBaseData(other, temp_clone)
- {
- duration = other.duration;
- n_loops = other.n_loops;
- dummy_fx_entry = other.dummy_fx_entry;
- do_id_convert = other.do_id_convert; // --
- trigger_mask = other.trigger_mask;
- match_type = other.match_type;
- match_state = other.match_state;
- phrase_type = other.phrase_type;
- no_choreographer_trigs = other.no_choreographer_trigs;
- no_cons_trigs = other.no_cons_trigs;
- no_player_trigs = other.no_player_trigs;
- on_trig_cmd = other.on_trig_cmd;
- // fx_list; // -- ??
- }
- void afxPhraseEffectData::reloadReset()
- {
- fx_list.clear();
- }
- ImplementEnumType( afxPhraseEffect_MatchType, "Possible phrase effect match types.\n" "@ingroup afxPhraseEffect\n\n" )
- { afxPhraseEffectData::MATCH_ANY, "any", "..." },
- { afxPhraseEffectData::MATCH_ALL, "all", "..." },
- EndImplementEnumType;
- ImplementEnumType( afxPhraseEffect_StateType, "Possible phrase effect state types.\n" "@ingroup afxPhraseEffect\n\n" )
- { afxPhraseEffectData::STATE_ON, "on", "..." },
- { afxPhraseEffectData::STATE_OFF, "off", "..." },
- { afxPhraseEffectData::STATE_ON_AND_OFF, "both", "..." },
- EndImplementEnumType;
- ImplementEnumType( afxPhraseEffect_PhraseType, "Possible phrase effect types.\n" "@ingroup afxPhraseEffect\n\n" )
- { afxPhraseEffectData::PHRASE_TRIGGERED, "triggered", "..." },
- { afxPhraseEffectData::PHRASE_CONTINUOUS, "continuous", "..." },
- EndImplementEnumType;
- #define myOffset(field) Offset(field, afxPhraseEffectData)
- void afxPhraseEffectData::initPersistFields()
- {
- addField("duration", TypeF32, myOffset(duration),
- "Specifies a duration for the phrase-effect. If set to infinity, the phrase-effect "
- "needs to have a phraseType of continuous. Set infinite duration using "
- "$AFX::INFINITE_TIME.");
- addField("numLoops", TypeS32, myOffset(n_loops),
- "Specifies the number of times the phrase-effect should loop. If set to infinity, "
- "the phrase-effect needs to have a phraseType of continuous. Set infinite looping "
- "using $AFX::INFINITE_REPEATS.");
- addField("triggerMask", TypeS32, myOffset(trigger_mask),
- "Sets which bits to consider in the current trigger-state which consists of 32 "
- "trigger-bits combined from (possibly overlapping) player trigger bits, constraint "
- "trigger bits, and choreographer trigger bits.");
- addField("matchType", TYPEID<afxPhraseEffectData::MatchType>(), myOffset(match_type),
- "Selects what combination of bits in triggerMask lead to a trigger. When set to "
- "'any', any bit in triggerMask matching the current trigger-state will cause a "
- "trigger. If set to 'all', every bit in triggerMask must match the trigger-state. "
- "Possible values: any or all.");
- addField("matchState", TYPEID<afxPhraseEffectData::StateType>(), myOffset(match_state),
- "Selects which bit-state(s) of bits in the triggerMask to consider when comparing to "
- "the current trigger-state. Possible values: on, off, or both.");
- addField("phraseType", TYPEID<afxPhraseEffectData::PhraseType>(), myOffset(phrase_type),
- "Selects between triggered and continuous types of phrases. When set to 'triggered', "
- "the phrase-effect is triggered when the relevant trigger-bits change state. When set "
- "to 'continuous', the phrase-effect will stay active as long as the trigger-bits "
- "remain in a matching state. Possible values: triggered or continuous.");
- addField("ignoreChoreographerTriggers", TypeBool, myOffset(no_choreographer_trigs),
- "When true, trigger-bits on the choreographer will be ignored.");
- addField("ignoreConstraintTriggers", TypeBool, myOffset(no_cons_trigs),
- "When true, animation triggers from dts-based constraint source objects will be "
- "ignored.");
- addField("ignorePlayerTriggers", TypeBool, myOffset(no_player_trigs),
- "When true, Player-specific triggers from Player-derived constraint source objects "
- "will be ignored.");
- addField("onTriggerCommand", TypeString, myOffset(on_trig_cmd),
- "Like a field substitution statement without the leading '$$' token, this eval "
- "statement will be executed when a trigger occurs. Any '%%' and '##' tokens will be "
- "substituted.");
- // effect lists
- // for each of these, dummy_fx_entry is set and then a validator adds it to the appropriate effects list
- static ewValidator emptyValidator(0);
- addFieldV("addEffect", TYPEID< afxEffectBaseData >(), myOffset(dummy_fx_entry), &emptyValidator,
- "A field macro which adds an effect wrapper datablock to a list of effects associated "
- "with the phrase-effect's single phrase. Unlike other fields, addEffect follows an "
- "unusual syntax. Order is important since the effects will resolve in the order they "
- "are added to each list.");
- Parent::initPersistFields();
- // disallow some field substitutions
- disableFieldSubstitutions("addEffect");
- }
- bool afxPhraseEffectData::onAdd()
- {
- if (Parent::onAdd() == false)
- return false;
- return true;
- }
- void afxPhraseEffectData::pack_fx(BitStream* stream, const afxEffectList& fx, bool packed)
- {
- stream->writeInt(fx.size(), EFFECTS_PER_PHRASE_BITS);
- for (int i = 0; i < fx.size(); i++)
- writeDatablockID(stream, fx[i], packed);
- }
- void afxPhraseEffectData::unpack_fx(BitStream* stream, afxEffectList& fx)
- {
- fx.clear();
- S32 n_fx = stream->readInt(EFFECTS_PER_PHRASE_BITS);
- for (int i = 0; i < n_fx; i++)
- fx.push_back((afxEffectWrapperData*)(uintptr_t)readDatablockID(stream));
- }
- void afxPhraseEffectData::packData(BitStream* stream)
- {
- Parent::packData(stream);
- stream->write(duration);
- stream->write(n_loops);
- stream->write(trigger_mask);
- stream->writeInt(match_type, 1);
- stream->writeInt(match_state, 2);
- stream->writeInt(phrase_type, 1);
- stream->writeFlag(no_choreographer_trigs);
- stream->writeFlag(no_cons_trigs);
- stream->writeFlag(no_player_trigs);
- stream->writeString(on_trig_cmd);
- pack_fx(stream, fx_list, mPacked);
- }
- void afxPhraseEffectData::unpackData(BitStream* stream)
- {
- Parent::unpackData(stream);
- stream->read(&duration);
- stream->read(&n_loops);
- stream->read(&trigger_mask);
- match_type = stream->readInt(1);
- match_state = stream->readInt(2);
- phrase_type = stream->readInt(1);
- no_choreographer_trigs = stream->readFlag();
- no_cons_trigs = stream->readFlag();
- no_player_trigs = stream->readFlag();
- on_trig_cmd = stream->readSTString();
- do_id_convert = true;
- unpack_fx(stream, fx_list);
- }
- bool afxPhraseEffectData::preload(bool server, String &errorStr)
- {
- if (!Parent::preload(server, errorStr))
- return false;
- // Resolve objects transmitted from server
- if (!server)
- {
- if (do_id_convert)
- {
- for (S32 i = 0; i < fx_list.size(); i++)
- {
- SimObjectId db_id = SimObjectId((uintptr_t)fx_list[i]);
- if (db_id != 0)
- {
- // try to convert id to pointer
- if (!Sim::findObject(db_id, fx_list[i]))
- {
- Con::errorf(ConsoleLogEntry::General,
- "afxPhraseEffectData::preload() -- bad datablockId: 0x%x",
- db_id);
- }
- }
- }
- do_id_convert = false;
- }
- }
- return true;
- }
- void afxPhraseEffectData::gather_cons_defs(Vector<afxConstraintDef>& defs)
- {
- afxConstraintDef::gather_cons_defs(defs, fx_list);
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
- DefineEngineMethod( afxPhraseEffectData, pushEffect, void, ( afxEffectBaseData* effectData ),,
- "Add a child effect to a phrase effect datablock. Argument can be an afxEffectWrappperData or an afxEffectGroupData.\n" )
- {
- if (!effectData)
- {
- Con::errorf("afxPhraseEffectData::pushEffect() -- failed to resolve effect datablock.");
- return;
- }
- object->fx_list.push_back(effectData);
- }
- //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
|