summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bloodfields.stage152
-rw-r--r--src/functionfloat.cpp17
-rw-r--r--src/functionfloat.h16
-rw-r--r--src/functioninteger.cpp17
-rw-r--r--src/functioninteger.h16
-rw-r--r--src/functionrandom.cpp9
-rw-r--r--src/game.cpp4
-rw-r--r--src/gamebuilder.cpp2
-rw-r--r--src/parser.l8
-rw-r--r--src/parser.y6
-rw-r--r--src/variable.cpp34
-rw-r--r--support/vim/syntax/stage.vim2
-rw-r--r--test.stage12
13 files changed, 256 insertions, 39 deletions
diff --git a/bloodfields.stage b/bloodfields.stage
index 7b61dd4..91bee08 100644
--- a/bloodfields.stage
+++ b/bloodfields.stage
@@ -6,6 +6,11 @@ global
6 { 6 {
7 exit(); 7 exit();
8 } 8 }
9
10 command: "exit"
11 {
12 exit();
13 }
9} 14}
10 15
11situation <<start>> 16situation <<start>>
@@ -14,19 +19,19 @@ situation <<start>>
14 { 19 {
15 global.enemyTypes = { 20 global.enemyTypes = {
16 1: { 21 1: {
17 'name': 'Snail', 22 'name': 'snail',
18 'action': 'bites', 23 'action': 'oozes on',
19 'hp': 3, 24 'hp': 3,
20 'attack': 2 25 'attack': 2
21 }, 26 },
22 2: { 27 2: {
23 'name': 'Wolf', 28 'name': 'wolf',
24 'action': 'bites', 29 'action': 'bites',
25 'hp': 7, 30 'hp': 7,
26 'attack': 3 31 'attack': 3
27 }, 32 },
28 3: { 33 3: {
29 'name': 'Snake', 34 'name': 'snake',
30 'action': 'strikes at', 35 'action': 'strikes at',
31 'hp': 3, 36 'hp': 3,
32 'attack': 3 37 'attack': 3
@@ -35,17 +40,17 @@ situation <<start>>
35 40
36 global.enemyMods = { 41 global.enemyMods = {
37 1: { 42 1: {
38 'name': 'Pathetic', 43 'name': 'pathetic',
39 'hp': 0, 44 'hp': 0,
40 'attack': 0 45 'attack': 0
41 }, 46 },
42 2: { 47 2: {
43 'name': 'Sickly', 48 'name': 'sickly',
44 'hp': 3, 49 'hp': 3,
45 'attack': 1 50 'attack': 1
46 }, 51 },
47 3: { 52 3: {
48 'name': 'Wimpy', 53 'name': 'wimpy',
49 'hp': 5, 54 'hp': 5,
50 'attack': 2 55 'attack': 2
51 } 56 }
@@ -54,7 +59,9 @@ situation <<start>>
54 player.hpMax = 10; 59 player.hpMax = 10;
55 player.hpCur = player.hpMax; 60 player.hpCur = player.hpMax;
56 player.xp = 0; 61 player.xp = 0;
62 player.level = 1;
57 player.attack = 3; 63 player.attack = 3;
64 player.potions = 1;
58 65
59 global.bJustTravelled = false; 66 global.bJustTravelled = false;
60 67
@@ -64,16 +71,23 @@ situation <<start>>
64 71
65function status() 72function status()
66{ 73{
74 display('You have ' + (100-player.xp) + ' xp until your next level.');
67 display('You have ' + player.hpCur + ' of ' + player.hpMax + ' hp.'); 75 display('You have ' + player.hpCur + ' of ' + player.hpMax + ' hp.');
76 display('You are carrying ' + player.potions + ' potions.');
68} 77}
69 78
70function look() 79function look()
71{ 80{
72 if( exists(global.enemy) )then 81 if exists(global.enemy) then
73 { 82 {
74 display('''You are standing in a field of wheat. You see a ''' + 83 display('''You are standing in a field of wheat. You see a ''' +
75 global.enemy['name'] + ''' in front of you.'''); 84 global.enemy['name'] + ''' in front of you.''');
76 } 85 }
86 else if exists( global.treasure ) then
87 {
88 display('''You are standing in a field of wheat. You find a ''' +
89 global.treasure['name'] + ''' lying here!''');
90 }
77 else 91 else
78 { 92 {
79 display('''You are standing in a field of wheat.'''); 93 display('''You are standing in a field of wheat.''');
@@ -86,12 +100,24 @@ function mkEnemy()
86 eid = random( 1, 3 ); 100 eid = random( 1, 3 );
87 global.enemy = global.enemyTypes[eid]; 101 global.enemy = global.enemyTypes[eid];
88 102
89 mod = 1; 103 mod = player.level;
104 if mod > 3 then
105 {
106 mod = 3;
107 }
90 global.enemy['name'] = global.enemyMods[mod]['name'] + ' ' + 108 global.enemy['name'] = global.enemyMods[mod]['name'] + ' ' +
91 global.enemy['name']; 109 global.enemy['name'];
92 global.enemy['attack'] = global.enemy['attack'] + 110 global.enemy['attack'] = global.enemy['attack'] +
93 global.enemyMods[mod]['attack']; 111 global.enemyMods[mod]['attack'];
94 global.enemy['hp'] = global.enemy['hp'] + global.enemyMods[mod]['hp']; 112 global.enemy['hp'] = global.enemy['hp'] + global.enemyMods[mod]['hp'];
113 global.enemy['level'] = mod;
114}
115
116function mkTreasure()
117{
118 global.treasure = {
119 'name': 'potion'
120 };
95} 121}
96 122
97function rollAttack( attack ) 123function rollAttack( attack )
@@ -107,7 +133,26 @@ function playerAttack()
107 ' damage.'); 133 ' damage.');
108 if global.enemy['hp'] <= 0 then 134 if global.enemy['hp'] <= 0 then
109 { 135 {
110 display('You killed the ' + global.enemy['name'] + '!'); 136 xp = 10;
137 display('You killed the ' + global.enemy['name'] + '! You gained ' +
138 xp + ' experience points.');
139 player.xp += xp;
140 if player.xp >= 100 then
141 {
142 player.xp -= 100;
143 player.level += 1;
144 player.hpMax += integer(random(0.25,0.75)*player.hpMax);
145 player.hpCur = player.hpMax;
146 display("You have leveled! Welcome to level " + player.level );
147 }
148
149 select = random(1, 3);
150 if select == 1 then
151 {
152 display('It looks like the ' + global.enemy['name'] +
153 ' dropped something...');
154 mkTreasure();
155 }
111 delete( global.enemy ); 156 delete( global.enemy );
112 } 157 }
113} 158}
@@ -123,22 +168,37 @@ function enemyAttack()
123 display('The ' + global.enemy['name'] + ' killed you!'); 168 display('The ' + global.enemy['name'] + ' killed you!');
124 exit(); 169 exit();
125 } 170 }
171 else
172 {
173 display('''You have ''' + player.hpCur + ''' hp left.''');
174 }
126} 175}
127 176
128situation <<travel>> 177situation <<travel>>
129{ 178{
179 command: "hi"
180 {
181 display("Yup, you're in travel.");
182 }
183
130 enter 184 enter
131 { 185 {
132 delete( global.enemy ); 186 delete( global.enemy );
133 187
134 display('You wander aimlessly through the seemingly endless field of wheat.'); 188 display('You wander aimlessly through the seemingly endless field of wheat.');
135 189
136 select = random(1,3); 190 select = random(1,6);
137 if select == 1 then 191 if select <= 4 then // 66% of the time, enemy!
138 { 192 {
139 mkEnemy(); 193 mkEnemy();
140 display('''There's a ''' + global.enemy['name'] + ''' here!'''); 194 display('''There's a ''' + global.enemy['name'] + ''' here!''');
141 } 195 }
196 else if select == 6 then // 16% of the time, treasure!
197 {
198 mkTreasure();
199 display('''You find a ''' + global.treasure['name'] +
200 ''' lying here!''');
201 }
142 202
143 global.bJustTravelled = true; 203 global.bJustTravelled = true;
144 204
@@ -161,11 +221,64 @@ situation <<field>>
161 } 221 }
162 } 222 }
163 223
224 command: "take"
225 {
226 if exists(global.treasure) then
227 {
228 if global.treasure['name'] == 'potion' then
229 {
230 display('''You pickup the ''' + global.treasure['name'] +
231 ''' and put it in your pocket.''');
232 player.potions += 1;
233 delete( global.treasure );
234 }
235 }
236 else
237 {
238 display('''There's nothing here to take...''');
239 }
240 }
241
242 command: 'drink'
243 {
244 if player.potions == 0 then
245 {
246 display('''You don't have anything to drink!''');
247 }
248 else
249 {
250 if player.hpCur == player.hpMax then
251 {
252 display('''You're already as healthy as can be!
253 Save the potions for when you're more injured.''');
254 }
255 else
256 {
257 player.potions -= 1;
258 gain = integer( random( 0.25, 0.5 ) * player.hpMax );
259 player.hpCur += gain;
260 if player.hpCur > player.hpMax then
261 {
262 gain -= player.hpCur - player.hpMax;
263 player.hpCur = player.hpMax;
264 }
265 display('''That really hit the spot! The potion restored ''' +
266 gain + ''' hp!''');
267 goto( <<field>> );
268 }
269 }
270 }
271
164 command: "look" 272 command: "look"
165 { 273 {
166 look(); 274 look();
167 } 275 }
168 276
277 command: "status"
278 {
279 status();
280 }
281
169 command: "walk" 282 command: "walk"
170 { 283 {
171 if not exists(global.enemy) then 284 if not exists(global.enemy) then
@@ -174,11 +287,17 @@ situation <<field>>
174 } 287 }
175 else 288 else
176 { 289 {
177 display("You can't walk around with an enemy in front of you! 290 display("You can't leave, the " + global.enemy['name'] +
178 You can try to flee if you'd like..."); 291 ' is blocking your path.');
179 } 292 }
180 } 293 }
181 294
295 command: "help"
296 {
297 display("Available commands are: walk, status, look, attack, take,
298 drink");
299 }
300
182 setup 301 setup
183 { 302 {
184 look(); 303 look();
@@ -192,11 +311,6 @@ situation <<field>>
192 { 311 {
193 enemyAttack(); 312 enemyAttack();
194 } 313 }
195 status();
196// look();
197 }
198 else
199 {
200 } 314 }
201 global.bJustTravelled = false; 315 global.bJustTravelled = false;
202 } 316 }
diff --git a/src/functionfloat.cpp b/src/functionfloat.cpp
new file mode 100644
index 0000000..7d6a0a5
--- /dev/null
+++ b/src/functionfloat.cpp
@@ -0,0 +1,17 @@
1#include "functionfloat.h"
2
3#include "gamestate.h"
4
5FunctionFloat::FunctionFloat()
6{
7}
8
9FunctionFloat::~FunctionFloat()
10{
11}
12
13void FunctionFloat::call( class GameState &gState )
14{
15 gState.push( gState.popDeref().to( Variable::tFloat ) );
16}
17
diff --git a/src/functionfloat.h b/src/functionfloat.h
new file mode 100644
index 0000000..ca72151
--- /dev/null
+++ b/src/functionfloat.h
@@ -0,0 +1,16 @@
1#ifndef FUNCTION_FLOAT_H
2#define FUNCTION_FLOAT_H
3
4#include "function.h"
5
6class FunctionFloat : public Function
7{
8public:
9 FunctionFloat();
10 virtual ~FunctionFloat();
11
12 virtual Bu::String getName() const { return "float"; }
13 virtual void call( class GameState &gState );
14};
15
16#endif
diff --git a/src/functioninteger.cpp b/src/functioninteger.cpp
new file mode 100644
index 0000000..049f9ca
--- /dev/null
+++ b/src/functioninteger.cpp
@@ -0,0 +1,17 @@
1#include "functioninteger.h"
2
3#include "gamestate.h"
4
5FunctionInteger::FunctionInteger()
6{
7}
8
9FunctionInteger::~FunctionInteger()
10{
11}
12
13void FunctionInteger::call( class GameState &gState )
14{
15 gState.push( gState.popDeref().to( Variable::tInt ) );
16}
17
diff --git a/src/functioninteger.h b/src/functioninteger.h
new file mode 100644
index 0000000..2832c20
--- /dev/null
+++ b/src/functioninteger.h
@@ -0,0 +1,16 @@
1#ifndef FUNCTION_INTEGER_H
2#define FUNCTION_INTEGER_H
3
4#include "function.h"
5
6class FunctionInteger : public Function
7{
8public:
9 FunctionInteger();
10 virtual ~FunctionInteger();
11
12 virtual Bu::String getName() const { return "integer"; }
13 virtual void call( class GameState &gState );
14};
15
16#endif
diff --git a/src/functionrandom.cpp b/src/functionrandom.cpp
index 2665a14..ec302b3 100644
--- a/src/functionrandom.cpp
+++ b/src/functionrandom.cpp
@@ -20,10 +20,17 @@ void FunctionRandom::call( class GameState &gState )
20 if( vHigh.getType() != vLow.getType() ) 20 if( vHigh.getType() != vLow.getType() )
21 throw Bu::ExceptionBase("Different types in random!"); 21 throw Bu::ExceptionBase("Different types in random!");
22 22
23 double dRand = random()/(double)(RAND_MAX-1);
23 if( vLow.getType() == Variable::tInt ) 24 if( vLow.getType() == Variable::tInt )
24 { 25 {
25 gState.push( Variable( (int64_t)( 26 gState.push( Variable( (int64_t)(
26 (random()%(vHigh.getInt()-vLow.getInt()+1ll))+vLow.getInt() 27 (dRand*(vHigh.getInt()-vLow.getInt()+1ll))+vLow.getInt()
28 ) ) );
29 }
30 else if( vLow.getType() == Variable::tFloat )
31 {
32 gState.push( Variable( (double)(
33 (dRand*(vHigh.getFloat()-vLow.getFloat()))+vLow.getFloat()
27 ) ) ); 34 ) ) );
28 } 35 }
29} 36}
diff --git a/src/game.cpp b/src/game.cpp
index c19b039..3a432d9 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -5,6 +5,8 @@
5#include "functiondelete.h" 5#include "functiondelete.h"
6#include "functionexit.h" 6#include "functionexit.h"
7#include "functionrandom.h" 7#include "functionrandom.h"
8#include "functioninteger.h"
9#include "functionfloat.h"
8 10
9Game::Game() 11Game::Game()
10{ 12{
@@ -14,6 +16,8 @@ Game::Game()
14 addFunction( new FunctionDelete() ); 16 addFunction( new FunctionDelete() );
15 addFunction( new FunctionExit() ); 17 addFunction( new FunctionExit() );
16 addFunction( new FunctionRandom() ); 18 addFunction( new FunctionRandom() );
19 addFunction( new FunctionInteger() );
20 addFunction( new FunctionFloat() );
17} 21}
18 22
19Game::~Game() 23Game::~Game()
diff --git a/src/gamebuilder.cpp b/src/gamebuilder.cpp
index d04a642..3cf2e1f 100644
--- a/src/gamebuilder.cpp
+++ b/src/gamebuilder.cpp
@@ -88,7 +88,7 @@ void GameBuilder::beginSituationMode( Situation::Mode m )
88 88
89void GameBuilder::closeSituationMode() 89void GameBuilder::closeSituationMode()
90{ 90{
91 //sio << "Set situation mode " << eCurSitMode << " to " << *pCurRoot << sio.nl; 91// sio << "Set situation <<" << pCurSit->getName() << ">> mode " << eCurSitMode << " to " << *pCurRoot << sio.nl;
92 pCurSit->setAst( pCurRoot, eCurSitMode ); 92 pCurSit->setAst( pCurRoot, eCurSitMode );
93 pCurRoot = pCurNode = NULL; 93 pCurRoot = pCurNode = NULL;
94} 94}
diff --git a/src/parser.l b/src/parser.l
index 7b11765..e0bc340 100644
--- a/src/parser.l
+++ b/src/parser.l
@@ -67,7 +67,7 @@ null { return tokNull; }
67 67
68[a-zA-Z_][a-zA-Z0-9_]* { yylval->sValue = new Bu::String( yytext ); return tokIdent; } 68[a-zA-Z_][a-zA-Z0-9_]* { yylval->sValue = new Bu::String( yytext ); return tokIdent; }
69 69
70[1-9][0-9]* { 70-?[1-9][0-9]* {
71 yylval->iValue = strtoll( yytext, NULL, 10 ); 71 yylval->iValue = strtoll( yytext, NULL, 10 );
72 return tokInt; 72 return tokInt;
73} 73}
@@ -76,10 +76,10 @@ null { return tokNull; }
76 return tokInt; 76 return tokInt;
77} 77}
78 78
79([1-9][0-9]*)?\.[0-9]* { 79-?([1-9][0-9]*|0)?\.[0-9]* {
80 printf("Parsing float: %s\n", yytext ); 80// printf("Parsing float: %s\n", yytext );
81 yylval->dValue = strtod( yytext, NULL ); 81 yylval->dValue = strtod( yytext, NULL );
82 printf("Final float: %f\n", yylval->dValue ); 82// printf("Final float: %f\n", yylval->dValue );
83 return tokFloat; 83 return tokFloat;
84} 84}
85 85
diff --git a/src/parser.y b/src/parser.y
index 3dfd737..2e9eead 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -54,7 +54,7 @@ void yyerror( YYLTYPE *llocp, yyscan_t yyscanner, GameBuilder &, const char *err
54%token tokDo 54%token tokDo
55%token tokIn 55%token tokIn
56%token tokIf 56%token tokIf
57%token tokThen 57%token tokThen "then"
58%token tokElse 58%token tokElse
59%token tokNot 59%token tokNot
60%token tokCommand 60%token tokCommand
@@ -204,7 +204,9 @@ ifnext:
204 | tokElse { bld.addNode( AstNode::tScope ); } '{' cmpltExprList '}' { 204 | tokElse { bld.addNode( AstNode::tScope ); } '{' cmpltExprList '}' {
205 bld.closeNode(); 205 bld.closeNode();
206 } 206 }
207 | tokElse { bld.addNode( AstNode::tScope ); } ifbase 207 | tokElse { bld.addNode( AstNode::tScope ); } ifbase {
208 bld.closeNode();
209 }
208 ; 210 ;
209 211
210varRef: tokIdent { bld.addVarRef( *($1), sidLocal ); } 212varRef: tokIdent { bld.addVarRef( *($1), sidLocal ); }
diff --git a/src/variable.cpp b/src/variable.cpp
index 965e1af..2ea8334 100644
--- a/src/variable.cpp
+++ b/src/variable.cpp
@@ -463,7 +463,6 @@ Variable Variable::operator+( const Variable &rhs ) const
463 { 463 {
464 return *this + rhs.to( eNew ); 464 return *this + rhs.to( eNew );
465 } 465 }
466 throw VariableException("Adding between dissimilar types is not yet supported.");
467 } 466 }
468 else 467 else
469 { 468 {
@@ -509,7 +508,16 @@ Variable Variable::operator-( const Variable &rhs ) const
509{ 508{
510 if( eType != rhs.eType ) 509 if( eType != rhs.eType )
511 { 510 {
512 throw VariableException("Subtracting between dissimilar types is not yet supported."); 511 Type eNew = bestType( eType, rhs.eType );
512
513 if( eType != eNew )
514 {
515 return to( eNew ) - rhs;
516 }
517 else
518 {
519 return *this - rhs.to( eNew );
520 }
513 } 521 }
514 else 522 else
515 { 523 {
@@ -551,7 +559,16 @@ Variable Variable::operator*( const Variable &rhs ) const
551{ 559{
552 if( eType != rhs.eType ) 560 if( eType != rhs.eType )
553 { 561 {
554 throw VariableException("Subtracting between dissimilar types is not yet supported."); 562 Type eNew = bestType( eType, rhs.eType );
563
564 if( eType != eNew )
565 {
566 return to( eNew ) * rhs;
567 }
568 else
569 {
570 return *this * rhs.to( eNew );
571 }
555 } 572 }
556 else 573 else
557 { 574 {
@@ -592,7 +609,16 @@ Variable Variable::operator/( const Variable &rhs ) const
592{ 609{
593 if( eType != rhs.eType ) 610 if( eType != rhs.eType )
594 { 611 {
595 throw VariableException("Subtracting between dissimilar types is not yet supported."); 612 Type eNew = bestType( eType, rhs.eType );
613
614 if( eType != eNew )
615 {
616 return to( eNew ) / rhs;
617 }
618 else
619 {
620 return *this / rhs.to( eNew );
621 }
596 } 622 }
597 else 623 else
598 { 624 {
diff --git a/support/vim/syntax/stage.vim b/support/vim/syntax/stage.vim
index 34da126..45e1346 100644
--- a/support/vim/syntax/stage.vim
+++ b/support/vim/syntax/stage.vim
@@ -19,7 +19,7 @@ syn keyword Statement setup enter
19syn keyword Todo TODO FIXME XXX 19syn keyword Todo TODO FIXME XXX
20syn keyword Type function command situation game global player 20syn keyword Type function command situation game global player
21syn keyword Constant null true false 21syn keyword Constant null true false
22syn keyword Builtins display goto exists delete exit return 22syn keyword Builtins display goto exists delete exit return random integer float
23 23
24syn cluster CommentGroup contains=Todo 24syn cluster CommentGroup contains=Todo
25 25
diff --git a/test.stage b/test.stage
index 66a9b70..4ffec79 100644
--- a/test.stage
+++ b/test.stage
@@ -17,13 +17,11 @@ situation <<start>>
17{ 17{
18 setup 18 setup
19 { 19 {
20 stuff = {}; 20 for each i in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] do
21 stuff['bob'] = {'joe': 'hi', 'sub': {1: 5, 2: 8} }; 21 {
22 stuff['bob']['sub'][55] = "aoeu"; 22 display( random(0.25, 0.5)*10 );
23 stuff['bob'] = 'hia'; 23 }
24 stuff['joe'] = stuff['bob']; 24 display( 0.25 * 10.0 );
25 stuff['joe'] += 'aoeu';
26 display( stuff['bob']['sub'][55] );
27 exit(); 25 exit();
28 } 26 }
29 27