<commit_before>#include <cmath>
#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

#include "defs.hh"
#include "conf.hh"
#include "StringSet.hh"
#include "FactorEncoder.hh"
#include "Unigrams.hh"

using namespace std;

void assert_short_subwords(map<string, flt_type> &vocab,
                           const set<string> &chars,
                           flt_type val)
{
    for (auto it = chars.cbegin(); it != chars.cend(); ++it)
        if (vocab.find(*it) == vocab.end())
            vocab[*it] = val;
}

int main(int argc, char* argv[]) {

    conf::Config config;
    config("usage: g1g [OPTION...] WORDLIST VOCAB_INIT VOCAB_OUTNAME\n")
      ('h', "help", "", "", "display help")
      ('u', "cutoff=INT", "arg", "0", "Cutoff value for each iteration")
      ('c', "candidates=INT", "arg", "25000", "Number of subwords to consider for removal per iteration")
      ('r', "removals=INT", "arg", "500", "Number of removals per iteration")
      ('m', "min-length=INT", "arg", "2", "Minimum length of subwords to remove")
      ('v', "vocab-size=INT", "arg must", "", "Target vocabulary size (stopping criterion)")
      ('t', "temp-vocabs=INT", "arg", "0", "Write out intermediate vocabularies for #V mod INT == 0")
      ('f', "forward-backward", "", "", "Use Forward-backward segmentation instead of Viterbi");
    config.default_parse(argc, argv);
    if (config.arguments.size() != 3) config.print_help(stderr, 1);

    flt_type one_char_min_lp = -25.0;
    string wordlist_fname = config.arguments[0];
    string vocab_fname = config.arguments[1];
    string out_vocab_fname = config.arguments[2];
    float cutoff_value = config["cutoff"].get_float();
    int n_candidates_per_iter = config["candidates"].get_int();
    int removals_per_iter = config["removals"].get_int();
    int min_removal_length = config["min-length"].get_int();
    int target_vocab_size = config["vocab-size"].get_int();
    int temp_vocab_interval = config["temp-vocabs"].get_int();
    bool enable_forward_backward = config["forward-backward"].specified;

    cerr << "parameters, wordlist: " << wordlist_fname << endl;
    cerr << "parameters, initial vocabulary: " << vocab_fname << endl;
    cerr << "parameters, cutoff: " << setprecision(15) << cutoff_value << endl;
    cerr << "parameters, candidates per iteration: " << n_candidates_per_iter << endl;
    cerr << "parameters, minimum length for subwords to remove: " << min_removal_length << endl;
    cerr << "parameters, removals per iteration: " << removals_per_iter << endl;
    cerr << "parameters, target vocab size: " << target_vocab_size << endl;
    if (temp_vocab_interval > 0)
        cerr << "parameters, write temp vocabs: " << temp_vocab_interval << endl;
    else
        cerr << "parameters, write temp vocabs: NO" << endl;
    cerr << "parameters, use forward-backward: " << enable_forward_backward << endl;

    int maxlen, word_maxlen;
    set<string> short_subwords;
    map<string, flt_type> vocab;
    map<string, flt_type> freqs;
    map<string, flt_type> words;

    cerr << "Reading vocabulary " << vocab_fname << endl;
    int retval = Unigrams::read_vocab(vocab_fname, vocab, maxlen);
    if (retval < 0) {
        cerr << "something went wrong reading vocabulary" << endl;
        exit(0);
    }
    cerr << "\t" << "size: " << vocab.size() << endl;
    cerr << "\t" << "maximum string length: " << maxlen << endl;
    for (auto it = vocab.cbegin(); it != vocab.end(); ++it) {
        if (it->first.length() < min_removal_length)
            short_subwords.insert(it->first);
    }

    cerr << "Reading word list " << wordlist_fname << endl;
    retval = Unigrams::read_vocab(wordlist_fname, words, word_maxlen);
    if (retval < 0) {
        cerr << "something went wrong reading word list" << endl;
        exit(0);
    }
    cerr << "\t" << "wordlist size: " << words.size() << endl;
    cerr << "\t" << "maximum word length: " << word_maxlen << endl;

    Unigrams gg;
    if (enable_forward_backward)
        gg.set_segmentation_method(forward_backward);
    else
        gg.set_segmentation_method(viterbi);

    cerr << "Initial cutoff" << endl;
    flt_type cost = gg.resegment_words(words, vocab, freqs);
    cerr << "cost: " << cost << endl;

    flt_type temp_cutoff = 1.0;
    while (true) {
        gg.cutoff(freqs, temp_cutoff, min_removal_length);
        cerr << "\tcutoff: " << temp_cutoff << "\t" << "vocabulary size: " << freqs.size() << endl;
        vocab = freqs;
        Unigrams::freqs_to_logprobs(vocab);
        assert_short_subwords(vocab, short_subwords, one_char_min_lp);
        temp_cutoff += 1.0;
        if (temp_cutoff > (flt_type)cutoff_value) break;
        cost = gg.resegment_words(words, vocab, freqs);
        cerr << "cost: " << cost << endl;
    }

    cerr << "Removing subwords one by one" << endl;
    int itern = 1;
    while (true) {

        cerr << "iteration " << itern << endl;

        cerr << "collecting candidate subwords for removal" << endl;
        set<string> candidates;
        if ((int)vocab.size()-n_candidates_per_iter < target_vocab_size) n_candidates_per_iter = (int)vocab.size()-target_vocab_size;
        gg.init_candidates_by_usage(words, vocab, candidates, n_candidates_per_iter/3, min_removal_length);
        gg.init_candidates_by_random(vocab, candidates, (n_candidates_per_iter-candidates.size())/3, min_removal_length);
        gg.init_candidates(vocab, candidates, n_candidates_per_iter-candidates.size(), min_removal_length);

        cerr << "ranking candidate subwords (" << candidates.size() << ")" << endl;
        vector<pair<string, flt_type> > removal_scores;
        cost = gg.rank_candidates(words, vocab, candidates, freqs, removal_scores);

        cerr << "starting cost before removing subwords one by one: " << cost << endl;

        // Remove subwords one by one
        unsigned int n_removals = 0;
        for (unsigned int i=0; i<removal_scores.size(); i++) {

            if (removal_scores[i].first.length() == 1) continue;
            // Score most probably went to zero already
            if (vocab.find(removal_scores[i].first) == vocab.end()) continue;
            if (freqs.find(removal_scores[i].first) == freqs.end()) continue;

            vocab.erase(removal_scores[i].first);
            freqs.erase(removal_scores[i].first);
            n_removals++;

            if (temp_vocab_interval > 0 && vocab.size() % temp_vocab_interval == 0) {
                vocab = freqs;
                Unigrams::freqs_to_logprobs(vocab);
                assert_short_subwords(vocab, short_subwords, one_char_min_lp);
                ostringstream vocabfname;
                vocabfname << "iteration_" << itern << "_" << vocab.size() << ".vocab";
                Unigrams::write_vocab(vocabfname.str(), vocab);
            }

            if (n_removals >= removals_per_iter) break;
            if (vocab.size() <= target_vocab_size) break;
        }

        int n_cutoff = Unigrams::cutoff(freqs, cutoff_value, min_removal_length);
        vocab = freqs;
        Unigrams::freqs_to_logprobs(vocab);
        assert_short_subwords(vocab, short_subwords, one_char_min_lp);
        cost = gg.iterate(words, vocab, 2);
        assert_short_subwords(vocab, short_subwords, one_char_min_lp);

        cerr << "subwords removed in this iteration: " << n_removals << endl;
        cerr << "subwords removed with cutoff this iteration: " << n_cutoff << endl;
        cerr << "current vocabulary size: " << vocab.size() << endl;
        cerr << "likelihood after the removals: " << cost << endl;

        itern++;

        if (vocab.size() <= target_vocab_size) {
            cerr << "stopping by min_vocab_size." << endl;
            break;
        }
    }

    exit(1);
}
<commit_msg>Write final vocabulary.<commit_after>#include <cmath>
#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

#include "defs.hh"
#include "conf.hh"
#include "StringSet.hh"
#include "FactorEncoder.hh"
#include "Unigrams.hh"

using namespace std;

void assert_short_subwords(map<string, flt_type> &vocab,
                           const set<string> &chars,
                           flt_type val)
{
    for (auto it = chars.cbegin(); it != chars.cend(); ++it)
        if (vocab.find(*it) == vocab.end())
            vocab[*it] = val;
}

int main(int argc, char* argv[]) {

    conf::Config config;
    config("usage: g1g [OPTION...] WORDLIST VOCAB_INIT VOCAB_OUTNAME\n")
      ('h', "help", "", "", "display help")
      ('u', "cutoff=INT", "arg", "0", "Cutoff value for each iteration")
      ('c', "candidates=INT", "arg", "25000", "Number of subwords to consider for removal per iteration")
      ('r', "removals=INT", "arg", "500", "Number of removals per iteration")
      ('m', "min-length=INT", "arg", "2", "Minimum length of subwords to remove")
      ('v', "vocab-size=INT", "arg must", "", "Target vocabulary size (stopping criterion)")
      ('t', "temp-vocabs=INT", "arg", "0", "Write out intermediate vocabularies for #V mod INT == 0")
      ('f', "forward-backward", "", "", "Use Forward-backward segmentation instead of Viterbi");
    config.default_parse(argc, argv);
    if (config.arguments.size() != 3) config.print_help(stderr, 1);

    flt_type short_subword_min_lp = -25.0;
    string wordlist_fname = config.arguments[0];
    string vocab_fname = config.arguments[1];
    string out_vocab_fname = config.arguments[2];
    float cutoff_value = config["cutoff"].get_float();
    int n_candidates_per_iter = config["candidates"].get_int();
    int removals_per_iter = config["removals"].get_int();
    int min_removal_length = config["min-length"].get_int();
    int target_vocab_size = config["vocab-size"].get_int();
    int temp_vocab_interval = config["temp-vocabs"].get_int();
    bool enable_forward_backward = config["forward-backward"].specified;

    cerr << "parameters, wordlist: " << wordlist_fname << endl;
    cerr << "parameters, initial vocabulary: " << vocab_fname << endl;
    cerr << "parameters, cutoff: " << setprecision(15) << cutoff_value << endl;
    cerr << "parameters, candidates per iteration: " << n_candidates_per_iter << endl;
    cerr << "parameters, minimum length for subwords to remove: " << min_removal_length << endl;
    cerr << "parameters, removals per iteration: " << removals_per_iter << endl;
    cerr << "parameters, target vocab size: " << target_vocab_size << endl;
    if (temp_vocab_interval > 0)
        cerr << "parameters, write temp vocabs: " << temp_vocab_interval << endl;
    else
        cerr << "parameters, write temp vocabs: NO" << endl;
    cerr << "parameters, use forward-backward: " << enable_forward_backward << endl;

    int maxlen, word_maxlen;
    set<string> short_subwords;
    map<string, flt_type> vocab;
    map<string, flt_type> freqs;
    map<string, flt_type> words;

    cerr << "Reading vocabulary " << vocab_fname << endl;
    int retval = Unigrams::read_vocab(vocab_fname, vocab, maxlen);
    if (retval < 0) {
        cerr << "something went wrong reading vocabulary" << endl;
        exit(0);
    }
    cerr << "\t" << "size: " << vocab.size() << endl;
    cerr << "\t" << "maximum string length: " << maxlen << endl;
    for (auto it = vocab.cbegin(); it != vocab.end(); ++it) {
        if (it->first.length() < min_removal_length)
            short_subwords.insert(it->first);
    }

    cerr << "Reading word list " << wordlist_fname << endl;
    retval = Unigrams::read_vocab(wordlist_fname, words, word_maxlen);
    if (retval < 0) {
        cerr << "something went wrong reading word list" << endl;
        exit(0);
    }
    cerr << "\t" << "wordlist size: " << words.size() << endl;
    cerr << "\t" << "maximum word length: " << word_maxlen << endl;

    Unigrams gg;
    if (enable_forward_backward)
        gg.set_segmentation_method(forward_backward);
    else
        gg.set_segmentation_method(viterbi);

    cerr << "Initial cutoff" << endl;
    flt_type cost = gg.resegment_words(words, vocab, freqs);
    cerr << "cost: " << cost << endl;

    flt_type temp_cutoff = 1.0;
    while (true) {
        gg.cutoff(freqs, temp_cutoff, min_removal_length);
        cerr << "\tcutoff: " << temp_cutoff << "\t" << "vocabulary size: " << freqs.size() << endl;
        vocab = freqs;
        Unigrams::freqs_to_logprobs(vocab);
        assert_short_subwords(vocab, short_subwords, short_subword_min_lp);
        temp_cutoff += 1.0;
        if (temp_cutoff > (flt_type)cutoff_value) break;
        cost = gg.resegment_words(words, vocab, freqs);
        cerr << "cost: " << cost << endl;
    }

    cerr << "Removing subwords one by one" << endl;
    int itern = 1;
    while (true) {

        cerr << "iteration " << itern << endl;

        cerr << "collecting candidate subwords for removal" << endl;
        set<string> candidates;
        if ((int)vocab.size()-n_candidates_per_iter < target_vocab_size) n_candidates_per_iter = (int)vocab.size()-target_vocab_size;
        gg.init_candidates_by_usage(words, vocab, candidates, n_candidates_per_iter/3, min_removal_length);
        gg.init_candidates_by_random(vocab, candidates, (n_candidates_per_iter-candidates.size())/3, min_removal_length);
        gg.init_candidates(vocab, candidates, n_candidates_per_iter-candidates.size(), min_removal_length);

        cerr << "ranking candidate subwords (" << candidates.size() << ")" << endl;
        vector<pair<string, flt_type> > removal_scores;
        cost = gg.rank_candidates(words, vocab, candidates, freqs, removal_scores);

        cerr << "starting cost before removing subwords one by one: " << cost << endl;

        // Remove subwords one by one
        unsigned int n_removals = 0;
        for (unsigned int i=0; i<removal_scores.size(); i++) {

            if (removal_scores[i].first.length() == 1) continue;
            // Score most probably went to zero already
            if (vocab.find(removal_scores[i].first) == vocab.end()) continue;
            if (freqs.find(removal_scores[i].first) == freqs.end()) continue;

            vocab.erase(removal_scores[i].first);
            freqs.erase(removal_scores[i].first);
            n_removals++;

            if (temp_vocab_interval > 0 && vocab.size() % temp_vocab_interval == 0) {
                vocab = freqs;
                Unigrams::freqs_to_logprobs(vocab);
                assert_short_subwords(vocab, short_subwords, short_subword_min_lp);
                ostringstream vocabfname;
                vocabfname << "iteration_" << itern << "_" << vocab.size() << ".vocab";
                Unigrams::write_vocab(vocabfname.str(), vocab);
            }

            if (n_removals >= removals_per_iter) break;
            if (vocab.size() <= target_vocab_size) break;
        }

        int n_cutoff = Unigrams::cutoff(freqs, cutoff_value, min_removal_length);
        vocab = freqs;
        Unigrams::freqs_to_logprobs(vocab);
        assert_short_subwords(vocab, short_subwords, short_subword_min_lp);
        cost = gg.iterate(words, vocab, 2);
        assert_short_subwords(vocab, short_subwords, short_subword_min_lp);

        cerr << "subwords removed in this iteration: " << n_removals << endl;
        cerr << "subwords removed with cutoff this iteration: " << n_cutoff << endl;
        cerr << "current vocabulary size: " << vocab.size() << endl;
        cerr << "likelihood after the removals: " << cost << endl;

        itern++;

        if (vocab.size() <= target_vocab_size) {
            cerr << "stopping by min_vocab_size." << endl;
            break;
        }
    }

    Unigrams::write_vocab(out_vocab_fname, vocab);
    exit(1);
}
<|endoftext|>


<commit_before>#include "../../include/widgets/StationListbox.hpp"
#include <nana/gui/widgets/form.hpp>

StationListbox::StationListbox(nana::form& handle, State::Context context)
    : nana::listbox(handle)
    , context_(context)
{
    this->append_header(context_.localizer_.get_localized_text("Station's name"));
    this->append_header(context_.localizer_.get_localized_text("URL"));
    this->append_header(context_.localizer_.get_localized_text("Country"));
    this->append_header(context_.localizer_.get_localized_text("Language"));
    this->append_header(context_.localizer_.get_localized_text("Codec"));
    this->append_header(context_.localizer_.get_localized_text("Bitrate"));
    this->append_header(context_.localizer_.get_localized_text("Tags"));
    this->column_at(Columns::Name).width(300u);
    this->column_at(Columns::Url).width(200u);
    this->column_at(Columns::Country).width(100u);
    this->column_at(Columns::Language).width(100u);
    this->column_at(Columns::Codec).width(50u);
    this->column_at(Columns::Bitrate).width(100u);
    this->column_at(Columns::Tags).width(100u);
    this->enable_single(false, false);
}

void StationListbox::populate_listbox(const std::vector<Station>& stations)
{
    if(!stations.empty())
    {
        this->auto_draw(false);
        this->clear();
        for (const auto& station : stations)
        {
            const auto category_index = Categories::NanaDefault;
            this->at(category_index).append(station);
        }
        this->auto_draw(true);
    }
}

std::optional<Station> StationListbox::get_selected_station() const
{
    if (!this->selected().empty())
    {
        const auto selected_item = this->selected().front();
        const auto category_index = static_cast<std::size_t>(Categories::NanaDefault);
        const auto column_index = static_cast<std::size_t>(Columns::Name);
        const auto station_category = this->at(category_index);
        const auto name = station_category.at(selected_item.item).text(column_index);
        const auto url = station_category.at(selected_item.item).text(static_cast<std::size_t>(Columns::Url));
        const auto country = station_category.at(selected_item.item).text(static_cast<std::size_t>(Columns::Country));
        const auto language = station_category.at(selected_item.item).text(static_cast<std::size_t>(Columns::Language));
        const auto codec = station_category.at(selected_item.item).text(static_cast<std::size_t>(Columns::Codec));
        const auto bitrate = station_category.at(selected_item.item).text(static_cast<std::size_t>(Columns::Bitrate));
        const auto tags = station_category.at(selected_item.item).text(static_cast<std::size_t>(Columns::Tags));
        return std::make_optional<Station>(name, url, country, language, codec, bitrate, tags);
    }
    return std::nullopt;

}

void StationListbox::select_from_position(const nana::arg_mouse& arg)
{
}

void StationListbox::sticky_select(const nana::arg_mouse& arg)
{
    if (!this->selected().empty())
    {
        for (const auto& pair : this->selected())
        {
            if (pair.item == this->selected().front().item)
            {
                continue;
            }
            else
            {
                this->at(pair.cat).at(pair.item).select(false);
            }
        }
    }
}
<commit_msg>StationListbox bug fixed.<commit_after>#include "../../include/widgets/StationListbox.hpp"
#include <nana/gui/widgets/form.hpp>

StationListbox::StationListbox(nana::form& handle, State::Context context)
    : nana::listbox(handle)
    , context_(context)
{
    this->append_header(context_.localizer_.get_localized_text("Station's name"));
    this->append_header(context_.localizer_.get_localized_text("URL"));
    this->append_header(context_.localizer_.get_localized_text("Country"));
    this->append_header(context_.localizer_.get_localized_text("Language"));
    this->append_header(context_.localizer_.get_localized_text("Codec"));
    this->append_header(context_.localizer_.get_localized_text("Bitrate"));
    this->append_header(context_.localizer_.get_localized_text("Tags"));
    this->column_at(Columns::Name).width(300u);
    this->column_at(Columns::Url).width(200u);
    this->column_at(Columns::Country).width(100u);
    this->column_at(Columns::Language).width(100u);
    this->column_at(Columns::Codec).width(50u);
    this->column_at(Columns::Bitrate).width(100u);
    this->column_at(Columns::Tags).width(100u);
    this->enable_single(false, false);
}

void StationListbox::populate_listbox(const std::vector<Station>& stations)
{
    this->auto_draw(false);
    this->clear();
    for (const auto& station : stations)
    {
        const auto category_index = Categories::NanaDefault;
        this->at(category_index).append(station);
    }
    this->auto_draw(true);
}

std::optional<Station> StationListbox::get_selected_station() const
{
    if (!this->selected().empty())
    {
        const auto selected_item = this->selected().front();
        const auto category_index = static_cast<std::size_t>(Categories::NanaDefault);
        const auto column_index = static_cast<std::size_t>(Columns::Name);
        const auto station_category = this->at(category_index);
        const auto name = station_category.at(selected_item.item).text(column_index);
        const auto url = station_category.at(selected_item.item).text(static_cast<std::size_t>(Columns::Url));
        const auto country = station_category.at(selected_item.item).text(static_cast<std::size_t>(Columns::Country));
        const auto language = station_category.at(selected_item.item).text(static_cast<std::size_t>(Columns::Language));
        const auto codec = station_category.at(selected_item.item).text(static_cast<std::size_t>(Columns::Codec));
        const auto bitrate = station_category.at(selected_item.item).text(static_cast<std::size_t>(Columns::Bitrate));
        const auto tags = station_category.at(selected_item.item).text(static_cast<std::size_t>(Columns::Tags));
        return std::make_optional<Station>(name, url, country, language, codec, bitrate, tags);
    }
    return std::nullopt;

}

void StationListbox::select_from_position(const nana::arg_mouse& arg)
{
}

void StationListbox::sticky_select(const nana::arg_mouse& arg)
{
    if (!this->selected().empty())
    {
        for (const auto& pair : this->selected())
        {
            if (pair.item == this->selected().front().item)
            {
                continue;
            }
            else
            {
                this->at(pair.cat).at(pair.item).select(false);
            }
        }
    }
}
<|endoftext|>


<commit_before>#ifndef G2_FIELD_CORE_INCLUDE_FIELD_STRUCTS_HH_
#define G2_FIELD_CORE_INCLUDE_FIELD_STRUCTS_HH_

/*===========================================================================*\

author: Matthias W. Smith
email:  mwsmith2@uw.edu
file:   field_constants.hh

about:  A header file for constant parameters used across field team
        software.

\*===========================================================================*/

//--- project includes  -----------------------------------------------------//
#include <vector>

//--- project includes  -----------------------------------------------------//
#include "field_constants.hh"

namespace g2field {

// A macro to define nmr structs since they are very similar.
#define MAKE_NMR_STRUCT(name, num_ch, len_tr)\
struct name {\
  Double_t sys_clock[num_ch];\
  Double_t gps_clock[num_ch];\
  Double_t dev_clock[num_ch];\
  Double_t snr[num_ch];\
  Double_t len[num_ch];\
  Double_t freq[num_ch];\
  Double_t ferr[num_ch];\
  Double_t freq_zc[num_ch];\
  Double_t ferr_zc[num_ch];\
  UShort_t health[num_ch];\
  UShort_t method[num_ch];\
  UShort_t trace[num_ch][len_tr];\
};

// Might as well define a root branch string for the struct.
#define MAKE_NMR_STRING(name, num_ch, len_tr) NMR_HELPER(name, num_ch, len_tr)

#define NMR_HELPER(name, num_ch, len_tr) \
const char * const name = "sys_clock["#num_ch"]/D:gps_clock["#num_ch"]/D:"\
"dev_clock["#num_ch"]/D:snr["#num_ch"]/D:len["#num_ch"]/D:freq["#num_ch"]/D:"\
"ferr["#num_ch"]/D:freq_zc["#num_ch"]/D:ferr_zc["#num_ch"]/D:"\
"health["#num_ch"]/s:method["#num_ch"]/s:trace["#num_ch"]["#len_tr"]/s"

// NMR structs
MAKE_NMR_STRUCT(fixed_t, NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_RECORD);
MAKE_NMR_STRING(fixed_str, NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_RECORD);

MAKE_NMR_STRUCT(online_fixed_t, NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_ONLINE);
MAKE_NMR_STRING(online_fixed_str, NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_ONLINE);

// Flexible struct built from the basic nmr attributes.
struct nmr_vector {
  std::vector<Double_t> sys_clock;
  std::vector<Double_t> gps_clock;
  std::vector<Double_t> dev_clock;
  std::vector<Double_t> snr;
  std::vector<Double_t> len;
  std::vector<Double_t> freq;
  std::vector<Double_t> ferr;
  std::vector<Double_t> freq_zc;
  std::vector<Double_t> ferr_zc;
  std::vector<UShort_t> health;
  std::vector<UShort_t> method;
  std::vector< std::array<UShort_t, NMR_FID_LENGTH_ONLINE> > trace;

  inline void Resize(int size) {
    sys_clock.resize(size);
    gps_clock.resize(size);
    dev_clock.resize(size);
    snr.resize(size);
    len.resize(size);
    freq.resize(size);
    ferr.resize(size);
    freq_zc.resize(size);
    ferr_zc.resize(size);
    health.resize(size);
    method.resize(size);
    trace.resize(size);
  }
};

//Trolley data structs
struct trolley_nmr_t{
  unsigned long int gps_clock;
  unsigned short probe_index;
  unsigned short length;
  short trace[TRLY_NMR_LENGTH];
};

#define MAKE_TLNMR_STRING(len) HELPER_TLNMR_STRING(len)
#define HELPER_TLNMR_STRING(len) \
const char * const trolley_nmr_str = "gps_clock/l:probe_index/s:len/s:trace["#len"]/s"
MAKE_TLNMR_STRING(TRLY_NMR_LENGTH);

struct trolley_barcode_t{
  unsigned long int gps_clock;
  unsigned short length_per_ch;
  unsigned short traces[TRLY_BARCODE_LENGTH]; //All channels
};

#define MAKE_BARCODE_STRING(len) HELPER_BARCODE_STRING(len)
#define HELPER_BARCODE_STRING(len) \
const char * const trolley_barcode_str = "gps_clock/l:len_per_ch/s:traces["#len"]/s"
MAKE_BARCODE_STRING(TRLY_BARCODE_LENGTH);

struct trolley_monitor_t{
  unsigned long int gps_clock_cycle_start;
  unsigned int PMonitorVal;
  unsigned int PMonitorTemp;
  unsigned int RFPower1;
  unsigned int RFPower2;
  unsigned int NMRCheckSum;
  unsigned int FrameCheckSum;
  unsigned int FrameSum;
  unsigned int FrameIndex;
  unsigned short StatusBits;
  unsigned short TMonitorIn;
  unsigned short TMonitorExt1;
  unsigned short TMonitorExt2;
  unsigned short TMonitorExt3;
  unsigned short V1Min;
  unsigned short V1Max;
  unsigned short V2Min;
  unsigned short V2Max;
  unsigned short length_per_ch;
  unsigned short trace_VMonitor1[TRLY_MONITOR_LENGTH];
  unsigned short trace_VMonitor2[TRLY_MONITOR_LENGTH];
};

#define MAKE_MONITOR_STRING(len) HELPER_MONITOR_STRING(len)
#define HELPER_MONITOR_STRING(len) \
const char * const trolley_monitor_str = "gps_clock_cycle_start/l:PMonitorVal/i:PMonitorTemp/i:RFPower1/i:RFPower2/i:"\
"NMRCheckSum/i:FrameCheckSum/i:FrameSum/i:StatusBits/s:"\
"TMonitorIn/s:TMonitorExt1/s:TMonitorExt2/s:TMonitorExt3/s:V1Min/s:V1Max/s:V2Min/s:V2Max/s:len_per_ch/s:"\
"trace_VMonitor1["#len"]/s:trace_VMonitor2["#len"]/s"
MAKE_MONITOR_STRING(TRLY_MONITOR_LENGTH);

//Surface coil struct
struct surface_coil_t{
  Double_t sys_clock[SC_NUM_COILS];
  Double_t gps_clock[SC_NUM_COILS];
  Double_t top_board[SC_NUM_COILS];
  Double_t bot_board[SC_NUM_COILS];
};

#define MAKE_SC_STRING(name,num_coils) SC_HELPER(name,num_coils)

#define SC_HELPER(name,num_coils)\
const char * const name = "sys_clock["#num_coils"]/D:gps_clock["#num_coils"]/D:top_board["#num_coils"]/D:bot_board["#num_coils"]/D"

MAKE_SC_STRING(sc_str,SC_NUM_COILS);

} // ::g2field

#endif
<commit_msg>Added temperature to surface coil struct<commit_after>#ifndef G2_FIELD_CORE_INCLUDE_FIELD_STRUCTS_HH_
#define G2_FIELD_CORE_INCLUDE_FIELD_STRUCTS_HH_

/*===========================================================================*\

author: Matthias W. Smith
email:  mwsmith2@uw.edu
file:   field_constants.hh

about:  A header file for constant parameters used across field team
        software.

\*===========================================================================*/

//--- project includes  -----------------------------------------------------//
#include <vector>

//--- project includes  -----------------------------------------------------//
#include "field_constants.hh"

namespace g2field {

// A macro to define nmr structs since they are very similar.
#define MAKE_NMR_STRUCT(name, num_ch, len_tr)\
struct name {\
  Double_t sys_clock[num_ch];\
  Double_t gps_clock[num_ch];\
  Double_t dev_clock[num_ch];\
  Double_t snr[num_ch];\
  Double_t len[num_ch];\
  Double_t freq[num_ch];\
  Double_t ferr[num_ch];\
  Double_t freq_zc[num_ch];\
  Double_t ferr_zc[num_ch];\
  UShort_t health[num_ch];\
  UShort_t method[num_ch];\
  UShort_t trace[num_ch][len_tr];\
};

// Might as well define a root branch string for the struct.
#define MAKE_NMR_STRING(name, num_ch, len_tr) NMR_HELPER(name, num_ch, len_tr)

#define NMR_HELPER(name, num_ch, len_tr) \
const char * const name = "sys_clock["#num_ch"]/D:gps_clock["#num_ch"]/D:"\
"dev_clock["#num_ch"]/D:snr["#num_ch"]/D:len["#num_ch"]/D:freq["#num_ch"]/D:"\
"ferr["#num_ch"]/D:freq_zc["#num_ch"]/D:ferr_zc["#num_ch"]/D:"\
"health["#num_ch"]/s:method["#num_ch"]/s:trace["#num_ch"]["#len_tr"]/s"

// NMR structs
MAKE_NMR_STRUCT(fixed_t, NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_RECORD);
MAKE_NMR_STRING(fixed_str, NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_RECORD);

MAKE_NMR_STRUCT(online_fixed_t, NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_ONLINE);
MAKE_NMR_STRING(online_fixed_str, NMR_NUM_FIXED_PROBES, NMR_FID_LENGTH_ONLINE);

// Flexible struct built from the basic nmr attributes.
struct nmr_vector {
  std::vector<Double_t> sys_clock;
  std::vector<Double_t> gps_clock;
  std::vector<Double_t> dev_clock;
  std::vector<Double_t> snr;
  std::vector<Double_t> len;
  std::vector<Double_t> freq;
  std::vector<Double_t> ferr;
  std::vector<Double_t> freq_zc;
  std::vector<Double_t> ferr_zc;
  std::vector<UShort_t> health;
  std::vector<UShort_t> method;
  std::vector< std::array<UShort_t, NMR_FID_LENGTH_ONLINE> > trace;

  inline void Resize(int size) {
    sys_clock.resize(size);
    gps_clock.resize(size);
    dev_clock.resize(size);
    snr.resize(size);
    len.resize(size);
    freq.resize(size);
    ferr.resize(size);
    freq_zc.resize(size);
    ferr_zc.resize(size);
    health.resize(size);
    method.resize(size);
    trace.resize(size);
  }
};

//Trolley data structs
struct trolley_nmr_t{
  unsigned long int gps_clock;
  unsigned short probe_index;
  unsigned short length;
  short trace[TRLY_NMR_LENGTH];
};

#define MAKE_TLNMR_STRING(len) HELPER_TLNMR_STRING(len)
#define HELPER_TLNMR_STRING(len) \
const char * const trolley_nmr_str = "gps_clock/l:probe_index/s:len/s:trace["#len"]/s"
MAKE_TLNMR_STRING(TRLY_NMR_LENGTH);

struct trolley_barcode_t{
  unsigned long int gps_clock;
  unsigned short length_per_ch;
  unsigned short traces[TRLY_BARCODE_LENGTH]; //All channels
};

#define MAKE_BARCODE_STRING(len) HELPER_BARCODE_STRING(len)
#define HELPER_BARCODE_STRING(len) \
const char * const trolley_barcode_str = "gps_clock/l:len_per_ch/s:traces["#len"]/s"
MAKE_BARCODE_STRING(TRLY_BARCODE_LENGTH);

struct trolley_monitor_t{
  unsigned long int gps_clock_cycle_start;
  unsigned int PMonitorVal;
  unsigned int PMonitorTemp;
  unsigned int RFPower1;
  unsigned int RFPower2;
  unsigned int NMRCheckSum;
  unsigned int FrameCheckSum;
  unsigned int FrameSum;
  unsigned int FrameIndex;
  unsigned short StatusBits;
  unsigned short TMonitorIn;
  unsigned short TMonitorExt1;
  unsigned short TMonitorExt2;
  unsigned short TMonitorExt3;
  unsigned short V1Min;
  unsigned short V1Max;
  unsigned short V2Min;
  unsigned short V2Max;
  unsigned short length_per_ch;
  unsigned short trace_VMonitor1[TRLY_MONITOR_LENGTH];
  unsigned short trace_VMonitor2[TRLY_MONITOR_LENGTH];
};

#define MAKE_MONITOR_STRING(len) HELPER_MONITOR_STRING(len)
#define HELPER_MONITOR_STRING(len) \
const char * const trolley_monitor_str = "gps_clock_cycle_start/l:PMonitorVal/i:PMonitorTemp/i:RFPower1/i:RFPower2/i:"\
"NMRCheckSum/i:FrameCheckSum/i:FrameSum/i:StatusBits/s:"\
"TMonitorIn/s:TMonitorExt1/s:TMonitorExt2/s:TMonitorExt3/s:V1Min/s:V1Max/s:V2Min/s:V2Max/s:len_per_ch/s:"\
"trace_VMonitor1["#len"]/s:trace_VMonitor2["#len"]/s"
MAKE_MONITOR_STRING(TRLY_MONITOR_LENGTH);

//Surface coil struct
struct surface_coil_t{
  Double_t sys_clock;
  Double_t bot_coil_currents[SC_NUM_COILS];
  Double_t top_coil_currents[SC_NUM_COILS];
  Double_t bot_coil_temps[SC_NUM_COILS];
  Double_t top_coil_temps[SC_NUM_COILS];
};

#define MAKE_SC_STRING(name,num_coils) SC_HELPER(name,num_coils)

#define SC_HELPER(name,num_coils)\
const char * const name = "sys_clock/D:bot_coil_currents["#num_coils"]/D:top_coil_currents["#num_coils"]/D:bot_coil_temps["#num_coils"]/D:top_coil_temps["#num_coils"]/D"

MAKE_SC_STRING(sc_str,SC_NUM_COILS);

} // ::g2field

#endif
<|endoftext|>


<commit_before>//=============================================================================================================
/**
* @file     neuromag.cpp
* @author   Christoph Dinh <chdinh@nmr.mgh.harvard.edu>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     July, 2012
*
* @section  LICENSE
*
* Copyright (C) 2012, Christoph Dinh and Matti Hamalainen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that
* the following conditions are met:
*     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
*       following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
*       the following disclaimer in the documentation and/or other materials provided with the distribution.
*     * Neither the name of the Massachusetts General Hospital nor the names of its contributors may be used
*       to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MASSACHUSETTS GENERAL HOSPITAL BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* @brief    Contains the implementation of the Neuromag Class.
*
*/

//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include "neuromag.h"
#include "dacqserver.h"

//*************************************************************************************************************
//=============================================================================================================
// FIFF INCLUDES
//=============================================================================================================

#include "../../../MNE/fiff/fiff.h"
#include "../../../MNE/fiff/fiff_types.h"

//*************************************************************************************************************
//=============================================================================================================
// MNE INCLUDES
//=============================================================================================================

#include "../../../MNE/mne/mne.h"
#include "../../../MNE/mne/mne_epoch_data_list.h"

//*************************************************************************************************************
//=============================================================================================================
// QT INCLUDES
//=============================================================================================================

#include <QtCore/QtPlugin>
#include <QFile>
#include <QDebug>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace NeuromagPlugin;
using namespace FIFFLIB;
using namespace MNELIB;

//*************************************************************************************************************
//=============================================================================================================
// DEFINE MEMBER METHODS
//=============================================================================================================

Neuromag::Neuromag()
: m_pDacqServer(new DacqServer(this))
, m_pInfo(NULL)
, m_bIsRunning(false)
, m_iID(-1)
{
    this->setBufferSampleSize(100);
    m_pRawMatrixBuffer = NULL;
    this->init();
//    this->start();
}

//*************************************************************************************************************

Neuromag::~Neuromag()
{
    qDebug() << "Destroy Neuromag::~Neuromag()";

    delete m_pDacqServer;

    m_bIsRunning = false;
    QThread::wait();
}

//*************************************************************************************************************

QByteArray Neuromag::availableCommands()
{
    QByteArray t_blockCmdInfoList;

//    t_blockCmdInfoList.append(QString("\t### %1 connector###\r\n").arg(this->getName()));

    return t_blockCmdInfoList;
}

//*************************************************************************************************************

ConnectorID Neuromag::getConnectorID() const
{
    return _NEUROMAG;
}

//*************************************************************************************************************

const char* Neuromag::getName() const
{
    return "Neuromag Connector";
}

//*************************************************************************************************************

void Neuromag::init()
{

}

//*************************************************************************************************************

bool Neuromag::parseCommand(QStringList& p_sListCommand, QByteArray& p_blockOutputInfo)
{
    bool success = false;

    return success;
}

//*************************************************************************************************************

bool Neuromag::start()
{
    // Start thread
    m_pDacqServer->start();

    QThread::start();

    return true;
}

//*************************************************************************************************************

bool Neuromag::stop()
{
    m_bIsRunning = false;
    QThread::wait();//ToDo: This thread will never be terminated when circular buffer is blocking the thread (happens when circularbuffer is empty)

    m_pDacqServer->m_bIsRunning = false;
    m_pDacqServer->wait();

    qDebug() << "bool Neuromag::stop()";

    return true;
}

//*************************************************************************************************************

void Neuromag::releaseMeasInfo()
{
    if(m_pInfo)
        emit remitMeasInfo(m_iID, m_pInfo);
}

//*************************************************************************************************************

void Neuromag::requestMeasInfo(qint32 ID)
{
    m_iID = ID;

    if(m_pInfo)
        releaseMeasInfo();
    else
    {
        m_pDacqServer->m_bMeasInfoRequest = true;

        //This should never happen
        if(m_pDacqServer->isRunning())
        {
            m_pDacqServer->m_bIsRunning = false;
            m_pDacqServer->wait();
            m_pDacqServer->start();
        }
        //
        else
        {
            m_pDacqServer->start();
//            m_pDacqServer->wait();// until header reading finished
        }
    }
}

//*************************************************************************************************************

void Neuromag::requestMeas()
{
    qDebug() << "void Neuromag::requestMeas()";

    m_pDacqServer->m_bMeasRequest = true;
    this->start();
}

//*************************************************************************************************************

void Neuromag::requestMeasStop()
{
    this->stop();
}

//*************************************************************************************************************

void Neuromag::requestSetBufferSize(quint32 p_uiBuffSize)
{
    if(p_uiBuffSize > 0)
    {
        qDebug() << "void Neuromag::setBufferSize: " << p_uiBuffSize;

        this->stop();

        this->setBufferSampleSize(p_uiBuffSize);

        this->start();
    }
}

//*************************************************************************************************************

void Neuromag::run()
{
    m_bIsRunning = true;

    while(m_bIsRunning)
    {
        if(m_pRawMatrixBuffer)
        {
            // Pop available Buffers
            MatrixXf tmp = m_pRawMatrixBuffer->pop();
//            printf("%d raw buffer (%d x %d) generated\r\n", count, tmp.rows(), tmp.cols());

            emit remitRawBuffer(tmp);
        }
    }
}
<commit_msg>[bugfix] neuromag.cpp<commit_after>//=============================================================================================================
/**
* @file     neuromag.cpp
* @author   Christoph Dinh <chdinh@nmr.mgh.harvard.edu>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     July, 2012
*
* @section  LICENSE
*
* Copyright (C) 2012, Christoph Dinh and Matti Hamalainen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that
* the following conditions are met:
*     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
*       following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
*       the following disclaimer in the documentation and/or other materials provided with the distribution.
*     * Neither the name of the Massachusetts General Hospital nor the names of its contributors may be used
*       to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MASSACHUSETTS GENERAL HOSPITAL BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* @brief    Contains the implementation of the Neuromag Class.
*
*/

//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include "neuromag.h"
#include "dacqserver.h"

//*************************************************************************************************************
//=============================================================================================================
// FIFF INCLUDES
//=============================================================================================================

#include "../../../MNE/fiff/fiff.h"
#include "../../../MNE/fiff/fiff_types.h"

//*************************************************************************************************************
//=============================================================================================================
// MNE INCLUDES
//=============================================================================================================

#include "../../../MNE/mne/mne.h"
#include "../../../MNE/mne/mne_epoch_data_list.h"

//*************************************************************************************************************
//=============================================================================================================
// QT INCLUDES
//=============================================================================================================

#include <QtCore/QtPlugin>
#include <QFile>
#include <QDebug>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace NeuromagPlugin;
using namespace FIFFLIB;
using namespace MNELIB;

//*************************************************************************************************************
//=============================================================================================================
// DEFINE MEMBER METHODS
//=============================================================================================================

Neuromag::Neuromag()
: m_pDacqServer(new DacqServer(this))
, m_pInfo(NULL)
, m_bIsRunning(false)
, m_iID(-1)
{
    this->setBufferSampleSize(100);
    m_pRawMatrixBuffer = NULL;
    this->init();
//    this->start();
}

//*************************************************************************************************************

Neuromag::~Neuromag()
{
    qDebug() << "Destroy Neuromag::~Neuromag()";

    delete m_pDacqServer;

    m_bIsRunning = false;
    QThread::wait();
}

//*************************************************************************************************************

QByteArray Neuromag::availableCommands()
{
    QByteArray t_blockCmdInfoList;

//    t_blockCmdInfoList.append(QString("\t### %1 connector###\r\n").arg(this->getName()));

    return t_blockCmdInfoList;
}

//*************************************************************************************************************

ConnectorID Neuromag::getConnectorID() const
{
    return _NEUROMAG;
}

//*************************************************************************************************************

const char* Neuromag::getName() const
{
    return "Neuromag Connector";
}

//*************************************************************************************************************

void Neuromag::init()
{

}

//*************************************************************************************************************

bool Neuromag::parseCommand(QStringList& p_sListCommand, QByteArray& p_blockOutputInfo)
{
    bool success = false;

    return success;
}

//*************************************************************************************************************

bool Neuromag::start()
{
    // Start thread
    m_pDacqServer->start();

    QThread::start();

    return true;
}

//*************************************************************************************************************

bool Neuromag::stop()
{
    m_bIsRunning = false;
    QThread::wait();//ToDo: This thread will never be terminated when circular buffer is blocking the thread (happens when circularbuffer is empty)

    m_pDacqServer->m_bIsRunning = false;
    m_pDacqServer->wait();

    qDebug() << "bool Neuromag::stop()";

    return true;
}

//*************************************************************************************************************

void Neuromag::releaseMeasInfo()
{
    if(m_pInfo)
        emit remitMeasInfo(m_iID, *m_pInfo);
}

//*************************************************************************************************************

void Neuromag::requestMeasInfo(qint32 ID)
{
    m_iID = ID;

    if(m_pInfo)
        releaseMeasInfo();
    else
    {
        m_pDacqServer->m_bMeasInfoRequest = true;

        //This should never happen
        if(m_pDacqServer->isRunning())
        {
            m_pDacqServer->m_bIsRunning = false;
            m_pDacqServer->wait();
            m_pDacqServer->start();
        }
        //
        else
        {
            m_pDacqServer->start();
//            m_pDacqServer->wait();// until header reading finished
        }
    }
}

//*************************************************************************************************************

void Neuromag::requestMeas()
{
    qDebug() << "void Neuromag::requestMeas()";

    m_pDacqServer->m_bMeasRequest = true;
    this->start();
}

//*************************************************************************************************************

void Neuromag::requestMeasStop()
{
    this->stop();
}

//*************************************************************************************************************

void Neuromag::requestSetBufferSize(quint32 p_uiBuffSize)
{
    if(p_uiBuffSize > 0)
    {
        qDebug() << "void Neuromag::setBufferSize: " << p_uiBuffSize;

        this->stop();

        this->setBufferSampleSize(p_uiBuffSize);

        this->start();
    }
}

//*************************************************************************************************************

void Neuromag::run()
{
    m_bIsRunning = true;

    while(m_bIsRunning)
    {
        if(m_pRawMatrixBuffer)
        {
            // Pop available Buffers
            MatrixXf tmp = m_pRawMatrixBuffer->pop();
//            printf("%d raw buffer (%d x %d) generated\r\n", count, tmp.rows(), tmp.cols());

            emit remitRawBuffer(tmp);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "net/base/escape.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/WebKit/chromium/public/WebData.h"
#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
#include "third_party/WebKit/WebKit/chromium/public/WebScriptSource.h"
#include "third_party/WebKit/WebKit/chromium/public/WebView.h"
#include "webkit/tools/test_shell/test_shell.h"
#include "webkit/tools/test_shell/test_shell_test.h"

using WebKit::WebFrame;
using WebKit::WebScriptSource;
using WebKit::WebString;

#if defined(OS_WIN)
#define TEST_PLUGIN_NAME "npapi_test_plugin.dll"
#elif defined(OS_MACOSX)
#define TEST_PLUGIN_NAME "npapi_test_plugin.plugin"
#elif defined(OS_POSIX)
#define TEST_PLUGIN_NAME "libnpapi_test_plugin.so"
#endif

#if defined(OS_MACOSX)
#define TEST_PLUGIN_DIRECTORY "PlugIns"
#else
#define TEST_PLUGIN_DIRECTORY "plugins"
#endif

// Ignore these until 64-bit plugin build is fixed. http://crbug.com/18337
#if !defined(ARCH_CPU_64_BITS)
// Provides functionality for creating plugin tests.
class PluginTest : public TestShellTest {
 public:
  PluginTest() {
    FilePath executable_directory;
    PathService::Get(base::DIR_EXE, &executable_directory);
    plugin_src_ = executable_directory.AppendASCII(TEST_PLUGIN_NAME);
    CHECK(file_util::PathExists(plugin_src_));

    plugin_file_path_ = executable_directory.AppendASCII(TEST_PLUGIN_DIRECTORY);
    file_util::CreateDirectory(plugin_file_path_);

    plugin_file_path_ = plugin_file_path_.AppendASCII(TEST_PLUGIN_NAME);
  }

  void CopyTestPlugin() {
    ASSERT_TRUE(file_util::CopyDirectory(plugin_src_, plugin_file_path_, true));
  }

  void DeleteTestPlugin() {
    file_util::Delete(plugin_file_path_, true);
  }

  virtual void SetUp() {
    CopyTestPlugin();
    TestShellTest::SetUp();
  }

  virtual void TearDown() {
    DeleteTestPlugin();
    TestShellTest::TearDown();
  }

  FilePath plugin_src_;
  FilePath plugin_file_path_;
};

// Tests navigator.plugins.refresh() works.
TEST_F(PluginTest, Refresh) {
  std::string html = "\

Test running....
\
      \
      ";

  WebScriptSource call_check(
      WebString::fromUTF8("check();"));
  WebScriptSource refresh(
      WebString::fromUTF8("navigator.plugins.refresh(false)"));

  // Remove any leftover from previous tests if they exist.  We must also
  // refresh WebKit's plugin cache since it might have had an entry for the
  // test plugin from a previous test.
  DeleteTestPlugin();
  ASSERT_FALSE(file_util::PathExists(plugin_file_path_));
  test_shell_->webView()->mainFrame()->executeScript(refresh);

  test_shell_->webView()->mainFrame()->loadHTMLString(
      html, GURL("about:blank"));
  test_shell_->WaitTestFinished();

  std::string text;
  test_shell_->webView()->mainFrame()->executeScript(call_check);
  text = test_shell_->webView()->mainFrame()->contentAsText(10000).utf8();
  ASSERT_EQ(text, "FAIL");

  CopyTestPlugin();

  test_shell_->webView()->mainFrame()->executeScript(refresh);
  test_shell_->webView()->mainFrame()->executeScript(call_check);
  text = test_shell_->webView()->mainFrame()->contentAsText(10000).utf8();
  ASSERT_EQ(text, "DONE");
}

// Tests that if a frame is deleted as a result of calling NPP_HandleEvent, we
// don't crash.
TEST_F(PluginTest, DeleteFrameDuringEvent) {
  FilePath test_html = data_dir_;
  test_html = test_html.AppendASCII("plugins");
  test_html = test_html.AppendASCII("delete_frame.html");
  test_shell_->LoadFile(test_html);
  test_shell_->WaitTestFinished();

  WebKit::WebMouseEvent input;
  input.button = WebKit::WebMouseEvent::ButtonLeft;
  input.x = 50;
  input.y = 50;
  input.type = WebKit::WebInputEvent::MouseUp;
  test_shell_->webView()->handleInputEvent(input);

  // No crash means we passed.
}

#if defined(OS_WIN)
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lparam) {
  HWND* plugin_hwnd = reinterpret_cast<HWND*>(lparam);
  if (*plugin_hwnd) {
    // More than one child window found, unexpected.
    plugin_hwnd = NULL;
    return FALSE;
  }
  *plugin_hwnd = hwnd;
  return TRUE;
}

// Tests that hiding/showing the parent frame hides/shows the plugin.
TEST_F(PluginTest, PluginVisibilty) {
  FilePath test_html = data_dir_;
  test_html = test_html.AppendASCII("plugins");
  test_html = test_html.AppendASCII("plugin_visibility.html");
  test_shell_->LoadFile(test_html);
  test_shell_->WaitTestFinished();

  WebFrame* main_frame = test_shell_->webView()->mainFrame();
  HWND frame_hwnd = test_shell_->webViewWnd();
  HWND plugin_hwnd = NULL;
  EnumChildWindows(frame_hwnd, EnumChildProc,
      reinterpret_cast<LPARAM>(&plugin_hwnd));
  ASSERT_TRUE(plugin_hwnd != NULL);
  ASSERT_FALSE(IsWindowVisible(plugin_hwnd));

  main_frame->executeScript(WebString::fromUTF8("showPlugin(true)"));
  ASSERT_TRUE(IsWindowVisible(plugin_hwnd));

  main_frame->executeScript(WebString::fromUTF8("showFrame(false)"));
  ASSERT_FALSE(IsWindowVisible(plugin_hwnd));

  main_frame->executeScript(WebString::fromUTF8("showFrame(true)"));
  ASSERT_TRUE(IsWindowVisible(plugin_hwnd));
}
#endif
#endif //!ARCH_CPU_64_BITS
<commit_msg>Fix plugin tests on linux.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "net/base/escape.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/WebKit/chromium/public/WebData.h"
#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
#include "third_party/WebKit/WebKit/chromium/public/WebScriptSource.h"
#include "third_party/WebKit/WebKit/chromium/public/WebView.h"
#include "webkit/tools/test_shell/test_shell.h"
#include "webkit/tools/test_shell/test_shell_test.h"

using WebKit::WebFrame;
using WebKit::WebScriptSource;
using WebKit::WebString;

#if defined(OS_WIN)
#define TEST_PLUGIN_NAME "npapi_test_plugin.dll"
#elif defined(OS_MACOSX)
#define TEST_PLUGIN_NAME "npapi_test_plugin.plugin"
#elif defined(OS_POSIX)
#define TEST_PLUGIN_NAME "libnpapi_test_plugin.so"
#endif

#if defined(OS_MACOSX)
#define TEST_PLUGIN_DIRECTORY "PlugIns"
#else
#define TEST_PLUGIN_DIRECTORY "plugins"
#endif

// Ignore these until 64-bit plugin build is fixed. http://crbug.com/18337
#if !defined(ARCH_CPU_64_BITS)
// Provides functionality for creating plugin tests.
class PluginTest : public TestShellTest {
 public:
  PluginTest() {
    FilePath executable_directory;
    PathService::Get(base::DIR_EXE, &executable_directory);
    plugin_src_ = executable_directory.AppendASCII(TEST_PLUGIN_NAME);
    CHECK(file_util::PathExists(plugin_src_));

    plugin_file_path_ = executable_directory.AppendASCII(TEST_PLUGIN_DIRECTORY);
    file_util::CreateDirectory(plugin_file_path_);

    plugin_file_path_ = plugin_file_path_.AppendASCII(TEST_PLUGIN_NAME);
  }

  void CopyTestPlugin() {
    // On Linux, we need to delete before copying because if the plugin is a
    // hard link, the copy will fail.
    DeleteTestPlugin();
    ASSERT_TRUE(file_util::CopyDirectory(plugin_src_, plugin_file_path_, true));
  }

  void DeleteTestPlugin() {
    file_util::Delete(plugin_file_path_, true);
  }

  virtual void SetUp() {
    CopyTestPlugin();
    TestShellTest::SetUp();
  }

  virtual void TearDown() {
    DeleteTestPlugin();
    TestShellTest::TearDown();
  }

  FilePath plugin_src_;
  FilePath plugin_file_path_;
};

// Tests navigator.plugins.refresh() works.
TEST_F(PluginTest, Refresh) {
  std::string html = "\

Test running....
\
      \
      ";

  WebScriptSource call_check(
      WebString::fromUTF8("check();"));
  WebScriptSource refresh(
      WebString::fromUTF8("navigator.plugins.refresh(false)"));

  // Remove any leftover from previous tests if they exist.  We must also
  // refresh WebKit's plugin cache since it might have had an entry for the
  // test plugin from a previous test.
  DeleteTestPlugin();
  ASSERT_FALSE(file_util::PathExists(plugin_file_path_));
  test_shell_->webView()->mainFrame()->executeScript(refresh);

  test_shell_->webView()->mainFrame()->loadHTMLString(
      html, GURL("about:blank"));
  test_shell_->WaitTestFinished();

  std::string text;
  test_shell_->webView()->mainFrame()->executeScript(call_check);
  text = test_shell_->webView()->mainFrame()->contentAsText(10000).utf8();
  ASSERT_EQ(text, "FAIL");

  CopyTestPlugin();

  test_shell_->webView()->mainFrame()->executeScript(refresh);
  test_shell_->webView()->mainFrame()->executeScript(call_check);
  text = test_shell_->webView()->mainFrame()->contentAsText(10000).utf8();
  ASSERT_EQ(text, "DONE");
}

// Tests that if a frame is deleted as a result of calling NPP_HandleEvent, we
// don't crash.
TEST_F(PluginTest, DeleteFrameDuringEvent) {
  FilePath test_html = data_dir_;
  test_html = test_html.AppendASCII("plugins");
  test_html = test_html.AppendASCII("delete_frame.html");
  test_shell_->LoadFile(test_html);
  test_shell_->WaitTestFinished();

  WebKit::WebMouseEvent input;
  input.button = WebKit::WebMouseEvent::ButtonLeft;
  input.x = 50;
  input.y = 50;
  input.type = WebKit::WebInputEvent::MouseUp;
  test_shell_->webView()->handleInputEvent(input);

  // No crash means we passed.
}

#if defined(OS_WIN)
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lparam) {
  HWND* plugin_hwnd = reinterpret_cast<HWND*>(lparam);
  if (*plugin_hwnd) {
    // More than one child window found, unexpected.
    plugin_hwnd = NULL;
    return FALSE;
  }
  *plugin_hwnd = hwnd;
  return TRUE;
}

// Tests that hiding/showing the parent frame hides/shows the plugin.
TEST_F(PluginTest, PluginVisibilty) {
  FilePath test_html = data_dir_;
  test_html = test_html.AppendASCII("plugins");
  test_html = test_html.AppendASCII("plugin_visibility.html");
  test_shell_->LoadFile(test_html);
  test_shell_->WaitTestFinished();

  WebFrame* main_frame = test_shell_->webView()->mainFrame();
  HWND frame_hwnd = test_shell_->webViewWnd();
  HWND plugin_hwnd = NULL;
  EnumChildWindows(frame_hwnd, EnumChildProc,
      reinterpret_cast<LPARAM>(&plugin_hwnd));
  ASSERT_TRUE(plugin_hwnd != NULL);
  ASSERT_FALSE(IsWindowVisible(plugin_hwnd));

  main_frame->executeScript(WebString::fromUTF8("showPlugin(true)"));
  ASSERT_TRUE(IsWindowVisible(plugin_hwnd));

  main_frame->executeScript(WebString::fromUTF8("showFrame(false)"));
  ASSERT_FALSE(IsWindowVisible(plugin_hwnd));

  main_frame->executeScript(WebString::fromUTF8("showFrame(true)"));
  ASSERT_TRUE(IsWindowVisible(plugin_hwnd));
}
#endif
#endif //!ARCH_CPU_64_BITS
<|endoftext|>


<commit_before>/*
 * AscEmu Framework based on ArcEmu MMORPG Server
 * Copyright (c) 2014-2018 AscEmu Team <http://www.ascemu.org>
 * Copyright (C) 2008-2012 ArcEmu Team <http://www.ArcEmu.org/>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "Setup.h"
#include "Units/Summons/Summon.h"
#include "Management/Item.h"
#include "Management/ItemInterface.h"
#include "Map/MapMgr.h"
#include "Objects/Faction.h"
#include "Units/Creatures/Pet.h"
#include "Spell/Spell.h"
#include "Server/Script/ScriptMgr.h"
#include <Spell/Definitions/PowerType.h>

class ArmyOfTheDeadGhoulAI : public CreatureAIScript
{
    ADD_CREATURE_FACTORY_FUNCTION(ArmyOfTheDeadGhoulAI);
    explicit ArmyOfTheDeadGhoulAI(Creature* pCreature) : CreatureAIScript(pCreature)
    {
        getCreature()->GetAIInterface()->m_canMove = false;
    }

    void OnLoad()
    {
        RegisterAIUpdateEvent(200);

        if (getCreature()->isSummon())
        {
            Summon* s = static_cast<Summon*>(getCreature());

            float parent_bonus = s->getUnitOwner()->GetDamageDoneMod(SCHOOL_NORMAL) * 0.04f;

            s->setMinDamage(s->getMinDamage() + parent_bonus);
            s->setMaxDamage(s->getMaxDamage() + parent_bonus);
        }
    }

    void AIUpdate()
    {
        getCreature()->CastSpell(getCreature()->getGuid(), 20480, false);
        RemoveAIUpdateEvent();
        getCreature()->GetAIInterface()->m_canMove = true;
    }
};

class ShadowFiendAI : public CreatureAIScript
{
    ADD_CREATURE_FACTORY_FUNCTION(ShadowFiendAI);
    explicit ShadowFiendAI(Creature* pCreature) : CreatureAIScript(pCreature)
    {
    }

    void OnLoad()
    {
        if (getCreature()->isPet())
        {
            Pet* s = static_cast<Pet*>(getCreature());
            Player* owner = dynamic_cast<Player*>(s->getPlayerOwner());

            float owner_bonus = static_cast<float>(owner->GetDamageDoneMod(SCHOOL_SHADOW) * 0.375f); // 37.5%
            s->BaseAttackType = SCHOOL_SHADOW; // Melee hits are supposed to do damage with the shadow school
            s->setBaseAttackTime(MELEE, 1500); // Shadowfiend is supposed to do 10 attacks, sometimes it can be 11
            s->setMinDamage(s->getMinDamage() + owner_bonus);
            s->setMaxDamage(s->getMaxDamage() + owner_bonus);
            s->BaseDamage[0] += owner_bonus;
            s->BaseDamage[1] += owner_bonus;

            Unit* uTarget = s->GetMapMgr()->GetUnit(owner->getTargetGuid());
            if ((uTarget != NULL) && isAttackable(owner, uTarget))
            {
                s->GetAIInterface()->AttackReaction(uTarget, 1);
                s->GetAIInterface()->setNextTarget(uTarget);
            }
        }
    }
};

class MirrorImageAI : public CreatureAIScript
{
    ADD_CREATURE_FACTORY_FUNCTION(MirrorImageAI);
    explicit MirrorImageAI(Creature* pCreature) : CreatureAIScript(pCreature)
    {
    }

    void OnLoad()
    {
        if (getCreature()->isSummon())
        {
            Summon* s = static_cast<Summon*>(getCreature());
            Unit* owner = s->getUnitOwner();

            owner->CastSpell(getCreature(), 45204, true);   // clone me
            owner->CastSpell(getCreature(), 58838, true);   // inherit threat list

            // Mage mirror image spell
            if (getCreature()->getCreatedBySpellId() == 58833)
            {
                getCreature()->setMaxHealth(2500);
                getCreature()->setHealth(2500);
                getCreature()->setMaxPower(POWER_TYPE_MANA, owner->getMaxPower(POWER_TYPE_MANA));
                getCreature()->setPower(POWER_TYPE_MANA, owner->getPower(POWER_TYPE_MANA));

                DBC::Structures::SpellRangeEntry const* range = NULL;

                AI_Spell sp1;
                sp1.entryId = 59638;
                sp1.spell = sSpellCustomizations.GetSpellInfo(sp1.entryId);
                if (!sp1.spell)
                    return;

                sp1.spellType = STYPE_DAMAGE;
                sp1.agent = AGENT_SPELL;
                sp1.spelltargetType = TTYPE_SINGLETARGET;
                sp1.cooldown = 0;
                sp1.cooldowntime = 0;
                sp1.Misc2 = 0;
                sp1.procCount = 0;
                sp1.procChance = 100;
                range = sSpellRangeStore.LookupEntry(sp1.spell->getRangeIndex());
                sp1.minrange = GetMinRange(range);
                sp1.maxrange = GetMaxRange(range);

                getCreature()->GetAIInterface()->addSpellToList(&sp1);

                AI_Spell sp2;
                sp2.entryId = 59637;
                sp2.spell = sSpellCustomizations.GetSpellInfo(sp2.entryId);
                if (!sp2.spell)
                    return;

                sp2.spellType = STYPE_DAMAGE;
                sp2.agent = AGENT_SPELL;
                sp2.spelltargetType = TTYPE_SINGLETARGET;
                sp2.cooldown = 0;
                sp2.cooldowntime = 0;
                sp2.Misc2 = 0;
                sp2.procCount = 0;
                sp2.procChance = 100;
                range = sSpellRangeStore.LookupEntry(sp2.spell->getRangeIndex());
                sp2.minrange = GetMinRange(range);
                sp2.maxrange = GetMaxRange(range);

                getCreature()->GetAIInterface()->addSpellToList(&sp2);
            }
        }
    }
};

class DancingRuneWeaponAI : public CreatureAIScript
{
    ADD_CREATURE_FACTORY_FUNCTION(DancingRuneWeaponAI);
    explicit DancingRuneWeaponAI(Creature* pCreature) : CreatureAIScript(pCreature)
    {
        dpsCycle = 0;
        dpsSpell = 0;
    }

    void OnLoad() override
    {
        getCreature()->setDisplayId(getCreature()->GetCreatureProperties()->Female_DisplayID);
        getCreature()->setBaseAttackTime(MELEE, 2000);

        if (getCreature()->isSummon())
        {
            Summon* s = static_cast<Summon*>(getCreature());
            Unit* owner = s->getUnitOwner();

            if (owner->isPlayer())
            {
                Player* pOwner = static_cast<Player*>(owner);
                Item* item = pOwner->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND);

                if (item != NULL)
                {
                    for (uint8 si = 0; si < 5; si++)
                    {
                        if (item->getItemProperties()->Spells[si].Id == 0)
                            continue;

                        if (item->getItemProperties()->Spells[si].Trigger == CHANCE_ON_HIT)
                            procSpell[si] = item->getItemProperties()->Spells[si].Id;
                    }

                    s->setVirtualItemSlotId(MELEE, item->getEntry());
                    s->setBaseAttackTime(MELEE, item->getItemProperties()->Delay);
                }

#if VERSION_STRING == WotLK
                pOwner->setPower(POWER_TYPE_RUNIC_POWER, 0);
#endif
            }

            s->setMinDamage(float(owner->GetDamageDoneMod(SCHOOL_NORMAL)));
            s->setMaxDamage(float(owner->GetDamageDoneMod(SCHOOL_NORMAL)));
        }
    }

    void OnCombatStart(Unit* /*mTarget*/) override
    {
        RegisterAIUpdateEvent(getCreature()->getBaseAttackTime(MELEE));
    }

    void OnCombatStop(Unit* /*mTarget*/) override
    {
        RemoveAIUpdateEvent();
        dpsCycle = 0;
    }

    void AIUpdate() override
    {
        Unit* curtarget = getCreature()->GetAIInterface()->getNextTarget();
        if (!getCreature()->isCastingSpell() && curtarget)
        {
            switch (dpsCycle)
            {
                case 0:
                    dpsSpell = 49921; // Plague Strike
                    break;
                case 1:
                    dpsSpell = 49909; // Icy Touch
                    break;
                case 2:
                case 3:
                    dpsSpell = 55262; // Heart Strike x 2
                    break;
                case 4:
                    dpsSpell = 51425; // Obliterate
                    break;
                case 5:
                    dpsSpell = 49895; // Death Coil
                    break;
                case 6:
                case 7:
                    dpsSpell = 51425; // Obliterate x 2
                    break;
                case 8:
                case 9:
                    dpsSpell = 55262; // Heart Strike x 2
                    break;
                case 10:
                case 11:
                    dpsSpell = 49895; // Death Coil x 2
                    break;
            }
            dpsCycle++;
            if (dpsCycle > 11)
                dpsCycle = 0;

            SpellInfo* MyNextSpell = sSpellCustomizations.GetSpellInfo(dpsSpell);
            if (MyNextSpell != NULL)
                getCreature()->CastSpell(curtarget, MyNextSpell, true);

        }
    }

    void OnHit(Unit* mTarget, float /*fAmount*/) override
    {
        for (uint8 p = 0; p < 5; p++)
        {
            if (procSpell[p] != 0)
            {
                SpellInfo* mProc = sSpellCustomizations.GetSpellInfo(procSpell[p]);
                if (!mProc)
                    return;
                int x = Util::getRandomUInt(99);
                uint32 proc = mProc->getProcChance();
                if (proc < 1)
                    proc = 10; // Got to be fair :P

                if ((uint32)x <= proc)
                {
                    Unit* Vic = mProc->custom_self_cast_only ? getCreature() : mTarget;
                    getCreature()->CastSpell(Vic, mProc, true);
                }
            }
        }
    }
private:

    int dpsCycle;
    int dpsSpell;
    int procSpell[5];
};

class FrostBroodVanquisherAI : public CreatureAIScript
{
    ADD_CREATURE_FACTORY_FUNCTION(FrostBroodVanquisherAI);
    explicit FrostBroodVanquisherAI(Creature* pCreature) : CreatureAIScript(pCreature)
    {
    }

    void OnLoad()
    {
        getCreature()->setAnimationFlags(UNIT_BYTE1_FLAG_HOVER);
    }

    void OnLastPassengerLeft(Unit *passenger)
    {
        if (getCreature()->getSummonedByGuid() == passenger->getGuid())
            getCreature()->Despawn(1 * 1000, 0);
    }
};

void SetupPetAISpells(ScriptMgr* mgr)
{
    mgr->register_creature_script(24207, &ArmyOfTheDeadGhoulAI::Create);
    mgr->register_creature_script(19668, &ShadowFiendAI::Create);
    mgr->register_creature_script(27893, &DancingRuneWeaponAI::Create);
    mgr->register_creature_script(31216, &MirrorImageAI::Create);
    mgr->register_creature_script(28670, &FrostBroodVanquisherAI::Create);
};
<commit_msg>Style: Clean up PetAISpells.cpp<commit_after>/*
 * AscEmu Framework based on ArcEmu MMORPG Server
 * Copyright (c) 2014-2018 AscEmu Team <http://www.ascemu.org>
 * Copyright (C) 2008-2012 ArcEmu Team <http://www.ArcEmu.org/>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "Setup.h"
#include "Units/Summons/Summon.h"
#include "Management/Item.h"
#include "Management/ItemInterface.h"
#include "Map/MapMgr.h"
#include "Objects/Faction.h"
#include "Units/Creatures/Pet.h"
#include "Spell/Spell.h"
#include "Server/Script/ScriptMgr.h"
#include <Spell/Definitions/PowerType.h>

class ArmyOfTheDeadGhoulAI : public CreatureAIScript
{
    ADD_CREATURE_FACTORY_FUNCTION(ArmyOfTheDeadGhoulAI)
    explicit ArmyOfTheDeadGhoulAI(Creature* pCreature) : CreatureAIScript(pCreature)
    {
        getCreature()->GetAIInterface()->m_canMove = false;
    }

    void OnLoad() override
    {
        RegisterAIUpdateEvent(200);

        if (getCreature()->isSummon())
        {
            auto summon = dynamic_cast<Summon*>(getCreature());

            const auto parentBonus = summon->getUnitOwner()->GetDamageDoneMod(SCHOOL_NORMAL) * 0.04f;

            summon->setMinDamage(summon->getMinDamage() + parentBonus);
            summon->setMaxDamage(summon->getMaxDamage() + parentBonus);
        }
    }

    void AIUpdate() override
    {
        getCreature()->CastSpell(getCreature()->getGuid(), 20480, false);
        RemoveAIUpdateEvent();
        getCreature()->GetAIInterface()->m_canMove = true;
    }
};

class ShadowFiendAI : public CreatureAIScript
{
    ADD_CREATURE_FACTORY_FUNCTION(ShadowFiendAI)
    explicit ShadowFiendAI(Creature* pCreature) : CreatureAIScript(pCreature)
    {
    }

    void OnLoad() override
    {
        if (getCreature()->isPet())
        {
            auto pet = dynamic_cast<Pet*>(getCreature());
            auto playerOwner = dynamic_cast<Player*>(pet->getPlayerOwner());

            const auto ownerBonus = static_cast<float>(playerOwner->GetDamageDoneMod(SCHOOL_SHADOW) * 0.375f); // 37.5%
            pet->BaseAttackType = SCHOOL_SHADOW; // Melee hits are supposed to do damage with the shadow school
            pet->setBaseAttackTime(MELEE, 1500); // Shadowfiend is supposed to do 10 attacks, sometimes it can be 11
            pet->setMinDamage(pet->getMinDamage() + ownerBonus);
            pet->setMaxDamage(pet->getMaxDamage() + ownerBonus);
            pet->BaseDamage[0] += ownerBonus;
            pet->BaseDamage[1] += ownerBonus;

            const auto unitTarget = pet->GetMapMgr()->GetUnit(playerOwner->getTargetGuid());
            if (unitTarget != nullptr && isAttackable(playerOwner, unitTarget))
            {
                pet->GetAIInterface()->AttackReaction(unitTarget, 1);
                pet->GetAIInterface()->setNextTarget(unitTarget);
            }
        }
    }
};

class MirrorImageAI : public CreatureAIScript
{
    ADD_CREATURE_FACTORY_FUNCTION(MirrorImageAI)
    explicit MirrorImageAI(Creature* pCreature) : CreatureAIScript(pCreature)
    {
    }

    void OnLoad() override
    {
        if (getCreature()->isSummon())
        {
            auto summon = dynamic_cast<Summon*>(getCreature());
            auto unitOwner = summon->getUnitOwner();

            unitOwner->CastSpell(getCreature(), 45204, true);   // clone me
            unitOwner->CastSpell(getCreature(), 58838, true);   // inherit threat list

            // Mage mirror image spell
            if (getCreature()->getCreatedBySpellId() == 58833)
            {
                getCreature()->setMaxHealth(2500);
                getCreature()->setHealth(2500);
                getCreature()->setMaxPower(POWER_TYPE_MANA, unitOwner->getMaxPower(POWER_TYPE_MANA));
                getCreature()->setPower(POWER_TYPE_MANA, unitOwner->getPower(POWER_TYPE_MANA));

                DBC::Structures::SpellRangeEntry const* range = nullptr;

                AI_Spell sp1{};
                sp1.entryId = 59638;
                sp1.spell = sSpellCustomizations.GetSpellInfo(sp1.entryId);
                if (!sp1.spell)
                    return;

                sp1.spellType = STYPE_DAMAGE;
                sp1.agent = AGENT_SPELL;
                sp1.spelltargetType = TTYPE_SINGLETARGET;
                sp1.cooldown = 0;
                sp1.cooldowntime = 0;
                sp1.Misc2 = 0;
                sp1.procCount = 0;
                sp1.procChance = 100;
                range = sSpellRangeStore.LookupEntry(sp1.spell->getRangeIndex());
                sp1.minrange = GetMinRange(range);
                sp1.maxrange = GetMaxRange(range);

                getCreature()->GetAIInterface()->addSpellToList(&sp1);

                AI_Spell sp2{};
                sp2.entryId = 59637;
                sp2.spell = sSpellCustomizations.GetSpellInfo(sp2.entryId);
                if (!sp2.spell)
                    return;

                sp2.spellType = STYPE_DAMAGE;
                sp2.agent = AGENT_SPELL;
                sp2.spelltargetType = TTYPE_SINGLETARGET;
                sp2.cooldown = 0;
                sp2.cooldowntime = 0;
                sp2.Misc2 = 0;
                sp2.procCount = 0;
                sp2.procChance = 100;
                range = sSpellRangeStore.LookupEntry(sp2.spell->getRangeIndex());
                sp2.minrange = GetMinRange(range);
                sp2.maxrange = GetMaxRange(range);

                getCreature()->GetAIInterface()->addSpellToList(&sp2);
            }
        }
    }
};

class DancingRuneWeaponAI : public CreatureAIScript
{
    ADD_CREATURE_FACTORY_FUNCTION(DancingRuneWeaponAI)
    explicit DancingRuneWeaponAI(Creature* pCreature) : CreatureAIScript(pCreature)
    {
        dpsCycle = 0;
        dpsSpell = 0;
    }

    void OnLoad() override
    {
        getCreature()->setDisplayId(getCreature()->GetCreatureProperties()->Female_DisplayID);
        getCreature()->setBaseAttackTime(MELEE, 2000);

        if (getCreature()->isSummon())
        {
            auto summon = dynamic_cast<Summon*>(getCreature());
            auto unitOwner = summon->getUnitOwner();

            if (unitOwner->isPlayer())
            {
                auto playerOwner = dynamic_cast<Player*>(unitOwner);
                const auto item = playerOwner->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND);
                if (item != nullptr)
                {
                    for (uint8 si = 0; si < 5; si++)
                    {
                        if (item->getItemProperties()->Spells[si].Id == 0)
                            continue;

                        if (item->getItemProperties()->Spells[si].Trigger == CHANCE_ON_HIT)
                            procSpell[si] = item->getItemProperties()->Spells[si].Id;
                    }

                    summon->setVirtualItemSlotId(MELEE, item->getEntry());
                    summon->setBaseAttackTime(MELEE, item->getItemProperties()->Delay);
                }

#if VERSION_STRING == WotLK
                playerOwner->setPower(POWER_TYPE_RUNIC_POWER, 0);
#endif
            }

            summon->setMinDamage(float(unitOwner->GetDamageDoneMod(SCHOOL_NORMAL)));
            summon->setMaxDamage(float(unitOwner->GetDamageDoneMod(SCHOOL_NORMAL)));
        }
    }

    void OnCombatStart(Unit* /*mTarget*/) override
    {
        RegisterAIUpdateEvent(getCreature()->getBaseAttackTime(MELEE));
    }

    void OnCombatStop(Unit* /*mTarget*/) override
    {
        RemoveAIUpdateEvent();
        dpsCycle = 0;
    }

    void AIUpdate() override
    {
        const auto currentTarget = getCreature()->GetAIInterface()->getNextTarget();
        if (!getCreature()->isCastingSpell() && currentTarget)
        {
            switch (dpsCycle)
            {
                case 0:
                    dpsSpell = 49921; // Plague Strike
                    break;
                case 1:
                    dpsSpell = 49909; // Icy Touch
                    break;
                case 2:
                case 3:
                    dpsSpell = 55262; // Heart Strike x 2
                    break;
                case 4:
                    dpsSpell = 51425; // Obliterate
                    break;
                case 5:
                    dpsSpell = 49895; // Death Coil
                    break;
                case 6:
                case 7:
                    dpsSpell = 51425; // Obliterate x 2
                    break;
                case 8:
                case 9:
                    dpsSpell = 55262; // Heart Strike x 2
                    break;
                case 10:
                case 11:
                    dpsSpell = 49895; // Death Coil x 2
                    break;
            default:
                break;
            }
            dpsCycle++;

            if (dpsCycle > 11)
                dpsCycle = 0;

            const auto nextSpell = sSpellCustomizations.GetSpellInfo(dpsSpell);
            if (nextSpell)
                getCreature()->CastSpell(currentTarget, nextSpell, true);
        }
    }

    void OnHit(Unit* mTarget, float /*fAmount*/) override
    {
        for (auto p : procSpell)
        {
            if (p != 0)
            {
                const auto spellProc = sSpellCustomizations.GetSpellInfo(p);
                if (!spellProc)
                    return;

                const auto randomProcChance = Util::getRandomUInt(99);
                uint32_t spellProcChance = spellProc->getProcChance();
                if (spellProcChance < 1)
                    spellProcChance = 10; // Got to be fair :P

                if (randomProcChance <= spellProcChance)
                {
                    const auto victim = spellProc->custom_self_cast_only ? getCreature() : mTarget;
                    getCreature()->CastSpell(victim, spellProc, true);
                }
            }
        }
    }
private:

    int dpsCycle;
    int dpsSpell;
    int procSpell[5];
};

class FrostBroodVanquisherAI : public CreatureAIScript
{
    ADD_CREATURE_FACTORY_FUNCTION(FrostBroodVanquisherAI)
    explicit FrostBroodVanquisherAI(Creature* pCreature) : CreatureAIScript(pCreature)
    {
    }

    void OnLoad() override
    {
        getCreature()->setAnimationFlags(UNIT_BYTE1_FLAG_HOVER);
    }

    void OnLastPassengerLeft(Unit *passenger) override
    {
        if (getCreature()->getSummonedByGuid() == passenger->getGuid())
            getCreature()->Despawn(1 * 1000, 0);
    }
};

void SetupPetAISpells(ScriptMgr* mgr)
{
    mgr->register_creature_script(24207, &ArmyOfTheDeadGhoulAI::Create);
    mgr->register_creature_script(19668, &ShadowFiendAI::Create);
    mgr->register_creature_script(27893, &DancingRuneWeaponAI::Create);
    mgr->register_creature_script(31216, &MirrorImageAI::Create);
    mgr->register_creature_script(28670, &FrostBroodVanquisherAI::Create);
}
<|endoftext|>


<commit_before><commit_msg>Reverting my previous experiment.<commit_after><|endoftext|>