1
/****************************************************************************
2
3
This file is part of the wolfenqt project on http://qt.gitorious.org.
4
5
Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).*
6
All rights reserved.
7
8
Contact:  Nokia Corporation (qt-info@nokia.com)**
9
10
You may use this file under the terms of the BSD license as follows:
11
12
"Redistribution and use in source and binary forms, with or without
13
modification, are permitted provided that the following conditions are met:
14
* Redistributions of source code must retain the above copyright notice,
15
* this list of conditions and the following disclaimer.
16
* Redistributions in binary form must reproduce the above copyright notice,
17
* this list of conditions and the following disclaimer in the documentation
18
* and/or other materials provided with the distribution.
19
* Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the
20
* names of its contributors may be used to endorse or promote products
21
* derived from this software without specific prior written permission.
22
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
POSSIBILITY OF SUCH DAMAGE."
33
34
****************************************************************************/
35
#include "scriptwidget.h"
36
#include "mazescene.h"
37
#include "entity.h"
38
39
static QScriptValue qsRand(QScriptContext *, QScriptEngine *engine)
40
{
41
    QScriptValue value(engine, qrand() / (RAND_MAX + 1.0));
42
    return value;
43
}
44
45
void ScriptWidget::setPreset(int preset)
46
{
47
    const char *presets[] =
48
    {
49
        "// available functions:\n"
50
        "// entity.turnLeft()\n"
51
        "// entity.turnRight()\n"
52
        "// entity.turnTowards(x, y)\n"
53
        "// entity.walk()\n"
54
        "// entity.stop()\n"
55
        "// rand()\n"
56
        "// script.display()\n"
57
        "\n"
58
        "// available variables:\n"
59
        "// my_x\n"
60
        "// my_y\n"
61
        "// player_x\n"
62
        "// player_y\n"
63
        "// time\n"
64
        "\n"
65
        "entity.stop();\n",
66
        "entity.walk();\n"
67
        "if ((time % 20000) < 10000) {\n"
68
        "  entity.turnTowards(10, 2.5);\n"
69
        "  if (my_x >= 5.5)\n"
70
        "    entity.stop();\n"
71
        "} else {\n"
72
        "  entity.turnTowards(-10, 2.5);\n"
73
        "  if (my_x <= 2.5)\n"
74
        "    entity.stop();\n"
75
        "}\n",
76
        "dx = player_x - my_x;\n"
77
        "dy = player_y - my_y;\n"
78
        "if (dx * dx + dy * dy < 5) {\n"
79
        "  entity.stop();\n"
80
        "} else {\n"
81
        "  entity.walk();\n"
82
        "  entity.turnTowards(player_x, player_y);\n"
83
        "}\n"
84
    };
85
86
    m_sourceEdit->setPlainText(QLatin1String(presets[preset]));
87
}
88
89
ScriptWidget::ScriptWidget(MazeScene *scene, Entity *entity)
90
    : m_scene(scene)
91
    , m_entity(entity)
92
{
93
    new QVBoxLayout(this);
94
95
    m_statusView = new QLineEdit;
96
    m_statusView->setReadOnly(true);
97
    layout()->addWidget(m_statusView);
98
99
    m_sourceEdit = new QPlainTextEdit;
100
    layout()->addWidget(m_sourceEdit);
101
102
    QPushButton *compileButton = new QPushButton(QLatin1String("Compile"));
103
    layout()->addWidget(compileButton);
104
105
    QComboBox *combo = new QComboBox;
106
    layout()->addWidget(combo);
107
108
    combo->addItem(QLatin1String("Default"));
109
    combo->addItem(QLatin1String("Patrol"));
110
    combo->addItem(QLatin1String("Follow"));
111
112
    setPreset(0);
113
    connect(combo, SIGNAL(currentIndexChanged(int)), this, SLOT(setPreset(int)));
114
    connect(compileButton, SIGNAL(clicked()), this, SLOT(updateSource()));
115
116
    m_engine = new QScriptEngine(this);
117
    QScriptValue entityObject = m_engine->newQObject(m_entity);
118
    m_engine->globalObject().setProperty("entity", entityObject);
119
    QScriptValue widgetObject = m_engine->newQObject(this);
120
    m_engine->globalObject().setProperty("script", widgetObject);
121
    m_engine->globalObject().setProperty("rand", m_engine->newFunction(qsRand));
122
123
    m_engine->setProcessEventsInterval(5);
124
125
    resize(300, 400);
126
    updateSource();
127
128
    startTimer(50);
129
    m_time.start();
130
}
131
132
void ScriptWidget::timerEvent(QTimerEvent *)
133
{
134
    QPointF player = m_scene->camera().pos();
135
    QPointF entity = m_entity->pos();
136
137
    QScriptValue px(m_engine, player.x());
138
    QScriptValue py(m_engine, player.y());
139
    QScriptValue ex(m_engine, entity.x());
140
    QScriptValue ey(m_engine, entity.y());
141
    QScriptValue time(m_engine, m_time.elapsed());
142
143
    m_engine->globalObject().setProperty("player_x", px);
144
    m_engine->globalObject().setProperty("player_y", py);
145
    m_engine->globalObject().setProperty("my_x", ex);
146
    m_engine->globalObject().setProperty("my_y", ey);
147
    m_engine->globalObject().setProperty("time", time);
148
149
    m_engine->evaluate(m_source);
150
    if (m_engine->hasUncaughtException()) {
151
        QString text = m_engine->uncaughtException().toString();
152
        m_statusView->setText(text);
153
    }
154
}
155
156
void ScriptWidget::display(QScriptValue value)
157
{
158
    m_statusView->setText(value.toString());
159
}
160
161
void ScriptWidget::updateSource()
162
{
163
    bool wasEvaluating = m_engine->isEvaluating();
164
    if (wasEvaluating)
165
        m_engine->abortEvaluation();
166
167
    m_time.restart();
168
    m_source = m_sourceEdit->toPlainText();
169
    if (wasEvaluating)
170
        m_statusView->setText(QLatin1String("Aborted long running evaluation!"));
171
    else if (m_engine->canEvaluate(m_source))
172
        m_statusView->setText(QLatin1String("Evaluation succeeded"));
173
    else
174
        m_statusView->setText(QLatin1String("Evaluation failed"));
175
}