1// =============================================================
2// This (poorly named) squirrel file contains the code to handle interaction with map objects.
3// It is also the file that handles the story-related special events.
4//
5
6// Some definitions. Maybe this should live in its own file.
7MD2_STAND <- 0;
8MD2_RUN <- 1;
9MD2_ATTACK <- 2;
10MD2_PAIN1 <- 3;
11MD2_PAIN2 <- 4;
12MD2_PAIN3 <- 5;
13MD2_JUMP <- 6;
14MD2_FLIP <- 7;
15MD2_SALUTE <- 8;
16MD2_TAUNT <- 9;
17MD2_WAVE <- 10;
18MD2_POINT <- 11;
19MD2_CRSTAND <- 12;
20MD2_CRWALK <- 13;
21MD2_CRATTACK <- 14;
22MD2_CRPAIN <- 15;
23MD2_CRDEATH <- 16;
24MD2_DEATH1 <- 17;
25MD2_DEATH2 <- 18;
26MD2_DEATH3 <- 19;
27
28// weather constants
29WEATHER_CLEAR <- 0
30WEATHER_RAIN <- 1
31WEATHER_THUNDER <- 2
32WEATHER_FOG <- 4
33
34// Called when entering map (before pressing ok)
35function enterMap( mapName ) {
36  print( "Welcome to S.C.O.U.R.G.E.: Heroes of Lesser Renown\n" );
37  // print( "v" + scourgeGame.getVersion() + "\n" );
38	print( "v" + scourgeGame.getVersion() + "\n" );
39  print( "You are on the " + mapName + " map.\n" );
40	print( "Chapter=" + scourgeGame.getMission().getChapter() + " Depth=" + scourgeGame.getMission().getDungeonDepth() + "\n" );
41
42	if( scourgeGame.getMission().isStoryLineMission() && !scourgeGame.getMission().isReplayMap() ) {
43		switch( scourgeGame.getMission().getChapter() ) {
44		case 5: initChapter6(); break;
45		case 7: initChapter8(); break;
46		case 8: initChapter9(); break;
47		case 9: initChapter10(); break;
48		case 10: initChapter11(); break;
49		case 11: initChapter12(); break;
50		}
51	}
52}
53
54// Called when entering map (after pressing ok)
55function mapStarting( mapName ) {
56	if( mapName == "hq" ) {
57		startHqMovie();
58	}
59}
60
61// Called when exiting map
62function exitMap( mapName ) {
63  print( "Ending level.\n" );
64}
65
66function testMyco() {
67  i <- 0;
68  for( i = 0; i < scourgeGame.getMission().getCreatureCount(); i++ ) {
69    if( scourgeGame.getMission().getCreature(i).getMonsterType() == "Mycotharsius the Mad" ) {
70      scourgeGame.getMission().getCreature(i).startConversation();
71      break;
72    }
73  }
74}
75
76// Called when a creature dies (before it turns into a "corpse" container.)
77function creatureDeath( creature ) {
78  if( creature.getMonsterType() == "Mycotharsius the Mad" ) {
79    // Myco. starts a conversation before he dies, revealing much...
80		scourgeGame.getMission().setCompleted( true );
81    creature.startConversation( creature );
82  } else if( creature.getMonsterType() == "Mothrazu Pain Incarnate" ) {
83		scourgeGame.getMission().setCompleted( true );
84		scourgeGame.showTextMessage( _( "The creature once known as Mothrazu sinks to one knee... Her breath comes in sharp gasps, as she growls:||\"I curse you humans...You may have defeated me but by Amod's grace, I still have one task left...\"||She reaches into a pouch and throws something small and silvery into the grove of trees at the center of the room.||\"You will never find it... Karzul's gift will mature and continue where I failed. May the plants be merciful to your malevolent souls... Amod! I am close...\"||With that Mothrazu passes from this world." ) );
85	} else if( creature.getMonsterType() == "Karzul Agmordexu" ) {
86		startGameEndMovie();
87	}
88  return true;
89}
90
91function decideAction( creature ) {
92	if( creature.getMonsterType() == "Karzul Agmordexu" ) {
93		if( creature.getHp().tofloat() <= 150 ) {
94			// karzul can save 6 times
95			key <- encodeKeyForCreature( creature, "Karzul.save" );
96		  value <- scourgeGame.getValue( key );
97		  if( value == null ) value = "0";
98
99		  numValue <- value.tointeger();
100		  print( "numValue=" + numValue.tostring() + "\n" );
101
102		  if( numValue < 10 ) {
103		  	print( "healing!\n" );
104		  	scourgeGame.setValue( key, ( numValue + 1 ).tostring() );
105
106				// heal self via the conduit
107				scourgeGame.printMessage( _( "Karzul uses his infernal conduit and heals his wounds!" ) );
108				creature.setHp( creature.getHp() + ( rand() * 50.0 / RAND_MAX ).tointeger() );
109				scourgeGame.getMission().setMapEffect( creature.getX(), creature.getY(), 3, // map location
110				                                       "EFFECT_TELEPORT",  												// effect
111				                                       4, 4, 																	// base size
112				                                       0,																			// delay
113				                                       false,																	// forever
114				                                       0, 0, 0, 														// offset
115				                                       1.0, 0.05, 0.25 														// color
116																							);
117
118				i <- 0;
119				minion_count <- 0;
120				minion_type <- "Cerxezu Demon Lord";
121				max_minion_count <- 3;
122				minion <- null;
123				dead_mod <- scourgeGame.getStateModByName( "dead" );
124				for( i = 0; i < scourgeGame.getMission().getCreatureCount(); i++ ) {
125						minion = scourgeGame.getMission().getCreature( i );
126						if( minion.getSummoner() == creature && !minion.getStateMod( dead_mod ) ) {
127							minion_count++;
128						}
129				}
130
131				print( "minions=" + minion_count.tostring() + "\n" );
132				if( minion_count < max_minion_count ) {
133					print( "summoning!\n" );
134					// fixme: should count number of helpers
135					scourgeGame.printMessage( _( "Karzul commands his minions to surge forth and destroy his attackers!" ) );
136					for( i = 0; i < max_minion_count - minion_count; i++ ) {
137						minion = creature.summon( minion_type, 304, 433, 351, 464 );
138						print( "new minion at: " + minion.getX().tostring() + "," + minion.getY().tostring() + "\n");
139					}
140				}
141				return true;
142		  }
143		}
144	}
145	return false;
146}
147
148// return true if the click was handled from squirrel
149function useShape( x, y, z ) {
150	//print( "useShape:: x=" + x + " y=" + y + " z=" + z + " chapter=" + scourgeGame.getMission().getChapter() + " depth=" + scourgeGame.getMission().getDungeonDepth() + "\n" );
151	shape <- scourgeGame.getMission().getShape( x, y, z );
152	if( shape != null ) {
153		print( "Shape used: " + shape + "\n" );
154		print( "Depth: " + scourgeGame.getMission().getDungeonDepth() + "\n" );
155		if( scourgeGame.getMission().getShape( x, y, 6 ) == "RED_TELEPORTER" ) {
156			if( scourgeGame.getMission().getDungeonDepth() == 0 ) {
157				print( "...going down..." );
158				scourgeGame.getMission().descendDungeon( x, y, z );
159			} else {
160				print( "...going up..." );
161				scourgeGame.getMission().ascendDungeon( x, y, z );
162			}
163			return true;
164		} else if( shape == "TREE-EMERIL-TRUNK" || shape == "TREE-EMERIL-TOP" ) {
165			handleTreeOfEmeril();
166			return true;
167		} else if( shape == "EW_DOOR" &&
168				x == 351 && y == 396 &&
169				scourgeGame.getMission().getDungeonDepth() == 0 &&
170				scourgeGame.getMission().getChapter() == 11 ) {
171			startChapter12Movie();
172			return false;
173		}
174	}
175	return false;
176}
177
178// deities from spells.txt
179deities <- [
180  "Unamoin",    // Confrontation
181  "Soroughoz",  // Ambush Trickery and Deceit
182  "Xelphate", // History and Lore
183  "Garzul-Meg-Aonrod", // Life and Death,
184  "Minirmuir", // Divine Awareness
185  "Amod-Rheinur" // Nature
186];
187
188
189// Different actions based on pool's and player's deity
190// Some combination does good, some does bad stuff...
191function usePool( x, y, z ) {
192  print( "Clicked on x=" + x + " y=" + y + " z=" + z + "\n" );
193  deity <- scourgeGame.getDeityLocation( x, y, z );
194  print( "Deity=" + deity + "\n" );
195
196  player <- scourgeGame.getPlayer();
197  playersDeity <- player.getDeity();
198  print( "player's deity is: " + playersDeity + "\n" );
199
200  i <- 0;
201  deityIndex <- -1;
202  oppositeDeity <- null;
203  for( i = 0; i < deities.len(); i++ ) {
204    if( deity == deities[i] ) {
205      // a cheap way of calc. the opposite deity.
206      // only works for an even numbered pantheon. :-)
207      oppositeDeity = deities[ deities.len() - 1 - i ];
208      deityIndex = i;
209      break;
210    }
211  }
212  if( deityIndex == -1 ) {
213    // ERROR: something changed in spells.txt
214    print( "*** Error: unknonw deity: " + deity + " did something change in data/world/spells.txt?" );
215    return false;
216  }
217
218  print( "Opposite deity=" + oppositeDeity );
219
220  helped <- false;
221  if( deity == playersDeity ) {
222    scourgeGame.printMessage( format( _( "The mighty lord %s reaches towards you," ), deity ) );
223    if( !incrementDailyCount( player, "deity.help.lastDateUsed", 3 ) ) {
224      scourgeGame.playSound("pool-canthelp");
225      scourgeGame.printMessage( _( "...alas, the deity can aid you no more today." ) );
226    } else {
227      helped = true;
228      player.setHp( player.getHp() +
229                    ( rand() *
230                      ( 2.0 * player.getLevel().tofloat() ) /
231                      RAND_MAX ).tointeger() + 1 );
232      scourgeGame.playSound("pool-helped");
233      scourgeGame.printMessage( _( "...and fills your spirit with energy." ) );
234    }
235  } else if( oppositeDeity == playersDeity ) {
236    scourgeGame.printMessage( format( _( "Your presence angers the mighty lord %s!" ), deity ) );
237    player.takeDamage( ( rand() *
238                         ( 2.0 * player.getLevel().tofloat() ) /
239                         RAND_MAX ) + 1.0 );
240    scourgeGame.playSound("pool-punished");
241    scourgeGame.printMessage( _( "...the deity's wrath scours your flesh!" ) );
242  } else {
243    scourgeGame.playSound("pool-ignored");
244    scourgeGame.printMessage( format( _( "The mighty lord %s ignores you." ), deity ) );
245  }
246
247  // deity specific actions
248  if( helped ) {
249    mods <- [];
250    modIndex <- 0;
251    switch( deityIndex ) {
252    case 0: // unamoin, confrontation
253    player.setStateMod( scourgeGame.getStateModByName( "empowered" ), true );
254    player.setStateMod( scourgeGame.getStateModByName( "ac_protected" ), true );
255    break;
256    case 1: // Soroughoz, ambush, trickery and deceit
257    player.setStateMod( scourgeGame.getStateModByName( "blessed" ), true );
258    player.setStateMod( scourgeGame.getStateModByName( "magic_protected" ), true );
259    break;
260    case 2: // Xelphate, history & lore
261    mods = [ "drunk", "poisoned", "cursed" ];
262    for( i = 0; i < mods.len(); i++ ) {
263      modIndex = scourgeGame.getStateModByName( mods[i] );
264      if( player.getStateMod( modIndex ) ) player.setStateMod( modIndex, false );
265    }
266    break;
267    case 3: // Garzul-Meg-Aonrod, life-death
268    mods = [ "possessed", "blinded", "paralysed" ];
269    for( i = 0; i < mods.len(); i++ ) {
270      modIndex = scourgeGame.getStateModByName( mods[i] );
271      if( player.getStateMod( modIndex ) ) player.setStateMod( modIndex, false );
272    }
273    break;
274    case 4: // Minirmuir, Divine Awareness
275    player.setMp( player.getMp() +
276                  ( rand() *
277                    ( 2.0 * player.getLevel().tofloat() ) /
278                    RAND_MAX ).tointeger() + 1 );
279    break;
280    case 5: // Amod-Rheinur, nature
281    player.setThirst( 10 );
282    player.setHunger( 10 );
283    break;
284    }
285  }
286
287  // FIXME: sacrifizing money and items
288
289	return true;
290}
291
292// =============================================================
293// Item events: they're only called for party members
294//
295function equipItem( creature, item ) {
296  //print( "ITEM EVENT: equipItem, creature: " + creature.getName() + " item: " + item.getName() + "\n" );
297}
298
299function doffItem( creature, item ) {
300  //print( "ITEM EVENT: doffItem, creature: " + creature.getName() + " item: " + item.getName() + "\n" );
301}
302
303function startBattleWithItem( creature, item ) {
304  //print( "ITEM EVENT: startBattleWithItem, creature: " + creature.getName() + " item: " + item.getName() + "\n" );
305}
306
307// assume the global var "damage" is defined as for skills
308function useItemInAttack( creature, item ) {
309  if( item.getName() == "Brand of Iconoclast" ) {
310    useBrandOfIconoclast( creature, item );
311  }
312}
313
314// assume the global var "armor" is defined as for skills
315function useItemInDefense( creature, item ) {
316  print( "useItemInDefense, item=" + item.getName() + "\n" );
317}
318
319// assume the global var "damage" exists and contains the current amount of
320// damage caused by this weapon to attacker.getTargetCreature()
321// Change the value of damage to be more or less depending on items (etc)
322// held/equipped by the attacker or the target.
323//
324// Note: item can be null if attack is with bare hands
325function damageHandler( attacker, item ) {
326  if( attacker.getTargetCreature() != null ) {
327    equippedItem <- attacker.getTargetCreature().getEquippedItem( 4 );
328    if( equippedItem != null ) {
329      if( equippedItem.getName() == "Cloak of Safe Passage" ) damageHandlerCloakSafePass( attacker, item );
330    }
331  }
332}
333
334// assume the global var "spellDamage" exists and contains the current amount of
335// damage caused by this spell to caster.getTargetCreature()
336// Change the value of spellDamage to be more or less depending on items (etc)
337// held/equipped by the caster or the target.
338function spellDamageHandler( caster, spell ) {
339  if( caster.getTargetCreature() != null ) {
340    item <- caster.getTargetCreature().getEquippedItem( 4 );
341    if( item != null ) {
342      if( item.getName() == "Cloak of Hateful Vengeance" ) spellDamageHandlerCloakHateVen( caster, spell );
343    }
344  }
345}
346
347// The waitHandlerXYZ functions allow you to modify the 'wait' time of the
348// item, spell or skill used in a combat turn.
349// Assumem that a global variable named 'turnWait' exists. Change it to the
350// desired new value, or leave as is if no change is needed.
351function waitHandlerSkill( attacker, skillName ) {
352//	print( "waitHandlerSkill: " + attacker.getName() + " wait=" + turnWait + "\n" );
353}
354
355function waitHandlerSpell( caster, spell ) {
356//	print( "waitHandlerSpell: " + caster.getName() + " wait=" + turnWait + "\n" );
357	if( caster.hasCapability( "Speedy Casting" ) == true ) {
358		turnWait = turnWait * 0.75;
359		scourgeGame.printMessage( format( _( "%s conjures up magic with blinding speed!" ), caster.getName() ) );
360	}
361}
362
363// if item is null, it's a bare-handed attack
364function waitHandlerItem( attacker, item ) {
365//	print( "waitHandlerItem: " + attacker.getName() + " wait=" + turnWait + "\n" );
366}
367
368// =============================================================
369// Conversation methods
370//
371
372/**
373 * Called when conversing with someone.
374 * @param creature creature the name or type of the creature (npc) you are talking to
375 * @param question the first keyphrase in the list that was clicked (Look at the maps/*.cfg files for examples)
376 * @return the answer string or null for no special handling
377 */
378function converse( creature, question ) {
379  print( "Creature=" + creature.getName() + " question:" + question + "\n" );
380
381  // Orhithales will not give you information until the armor has been recovered
382  if( creature.getMonsterType() == "Orhithales Grimwise" &&
383      !( scourgeGame.getMission().isCompleted() ) &&
384      question == "SQ_DRAGONSCALE_ARMOR" ) {
385    return _( "Yes, yes... quite so... carry on!" );
386  } else if( creature.getMonsterType() == "Sabien Gartu" ) {
387		if( !( scourgeGame.getMission().isCompleted() ) &&
388			scourgeGame.getMission().getChapter() != 7 &&
389			question == "SQ_LOCKED_DOOR" ) {
390			scourgeGame.getMission().setCompleted();
391		} else if( scourgeGame.getMission().getChapter() == 7 ) {
392		  if( question == "SQ_AFTER" ) {
393        // remove map block at 294,223 to make door accessible
394        scourgeGame.getMission().removeMapPosition( 294, 223, 0 );
395      }
396    }
397  } else if( creature.getMonsterType() == "Karzul Agmordexu" &&
398             !( scourgeGame.getMission().isCompleted() ) &&
399             question == "SQ_SERVES" ) {
400    scourgeGame.getMission().setCompleted();
401  }	else if( creature.getMonsterType() == "Positive Energy of Hornaxx" ) {
402		if( question == "SQ_UNAMOIN" ) {
403			storePartyLevel();
404		} else if( question == "SQ_TOKENS" ) {
405			assignAntimagicItems();
406		}
407	} else if( creature.getMonsterType() == "Mothrazu" &&
408						 question == "SQ_DOOM" ) {
409		mothrazuTransforms( creature );
410	} else if( creature.getMonsterType() == "Spawn of Arcanex" ) {
411		if( !( scourgeGame.getMission().isCompleted() ) &&
412				question == "SQ_KARZUL" ) {
413			scourgeGame.getMission().setCompleted();
414		}
415	} else if( creature.getMonsterType() == "Nightlord" && question == "ready" ) {
416		teleportPartyToSurface();
417	}
418  return null;
419}
420
421function teleportPartyToSurface() {
422	// conversation ends
423	scourgeGame.endConversation();
424
425	// summon help. todo: use this value once on the surface
426	scourgeGame.setValue( "guardians_summoned", "true" );
427
428	// nightwards depart
429
430	// ascend!
431	scourgeGame.ascendToSurface();
432}
433
434function mothrazuTransforms( creature ) {
435	scourgeGame.endConversation();
436	replacement <- scourgeGame.getMission().
437		replaceCreature( creature,
438										 "Mothrazu Pain Incarnate" );
439	// statemod: 0,1,2,3,4 and 11 (blessed, empowered, enraged, ac_protected, magic_protected and invisible)
440	replacement.setStateMod( 0, true );
441	replacement.setStateMod( 1, true );
442	replacement.setStateMod( 2, true );
443	replacement.setStateMod( 3, true );
444	replacement.setStateMod( 4, true );
445	replacement.setStateMod( 11, true );
446}
447
448// =============================================================
449// Specific item handling
450function useBrandOfIconoclast( creature, item ) {
451  if( creature.getTargetCreature() != null &&
452      creature.getTargetCreature().getMaxMp() > 0 ) {
453    scourgeGame.printMessage( _( "...Brand of Iconoclast growls in a low tone..." ) );
454    delta <- ( damage / 100.0 ) * 10.0;
455    damage += delta;
456    if( delta.tointeger() > 0 ) {
457      scourgeGame.printMessage( format( _( "...damage is increased by %d pts!" ), delta.tointeger() ) );
458    }
459  }
460}
461
462// spell damage reduction when wearing the Cloak of Vengeance
463function spellDamageHandlerCloakHateVen( caster, spell ) {
464  if( spell.getDeity() == "Unamoin" && damage > 0 ) {
465
466    delta <- ( damage / 100.0 ) * 15.0;
467    damage += delta;
468    if( delta.tointeger() > 0 ) {
469      scourgeGame.printMessage( format( _( "...damage is reduced by %d pts! (Cloak of Hateful Vengeance)" ), delta.tointeger() ) );
470    }
471
472    incrementCloakHateVenUse( caster.getTargetCreature() );
473  }
474}
475
476function incrementCloakHateVenUse( target ) {
477  key <- encodeKeyForCreature( target, "CloakOfHatefulVengeance" );
478  value <- scourgeGame.getValue( key );
479  if( value == null ) numValue <- 0;
480  else numValue <- value.tointeger();
481  numValue++;
482  if( numValue >= 100 ) {
483    // FIXME: do something... cloak of hateful vengeance was used 100 times
484    scourgeGame.printMessage( "FIXME: do something! Cloak of Hateful Vengeance was used 100 times." );
485  }
486  print( "Cloak of hateful vengeance was used " + numValue + " times.\n" );
487  scourgeGame.setValue( key, numValue.tostring() );
488}
489
490function damageHandlerCloakSafePass( attacker, item ) {
491  if( damage > 0 ) {
492    delta <- ( damage / 100.0 ) * 10.0;
493    damage += delta;
494    if( delta.tointeger() > 0 ) {
495      scourgeGame.printMessage( format( _( "...damage is reduced by %d pts! (Cloak of Safe Passage)" ), delta.tointeger() ) );
496    }
497  }
498}
499
500// slow method, oh well
501function findCreatureByType( name ) {
502	i <- 0;
503	creature <- null;
504	for( i = 0; i < scourgeGame.getMission().getCreatureCount(); i++ ) {
505		creature = scourgeGame.getMission().getCreature( i );
506		if( creature.getMonsterType() == name ) {
507			return creature;
508		}
509	}
510	return null;
511}
512
513function dumpCreatures() {
514	i <- 0;
515	creature <- null;
516	for( i = 0; i < scourgeGame.getMission().getCreatureCount(); i++ ) {
517		creature = scourgeGame.getMission().getCreature( i );
518		print("i=" + i.tostring() + " creature=" + creature.getName() + " type=" + creature.getMonsterType() + "\n");
519	}
520}
521
522function initChapter6() {
523	// lock the door
524	if( scourgeGame.getMission().getDungeonDepth() == 3 ) {
525		scourgeGame.getMission().setDoorLocked( 292, 209, 0, true );
526	}
527}
528
529function initChapter8() {
530	// modify sabien's intro text
531	i <- 0;
532	if( scourgeGame.getMission().getDungeonDepth() == 0 ) {
533
534		// unlock the door
535		scourgeGame.getMission().setDoorLocked( 292, 209, 0, false );
536
537		for( i = 0; i < scourgeGame.getMission().getCreatureCount(); i++ ) {
538			if( scourgeGame.getMission().getCreature( i ).getMonsterType() == "Sabien Gartu" ) {
539				scourgeGame.getMission().getCreature( i ).setIntro( "SQ_CHAPTER_8" );
540				break;
541			}
542		}
543	} else if( scourgeGame.getMission().getDungeonDepth() == 1 ) {
544		// everyone is cursed and poisoned
545		i	<- 0;
546		for( i = 0; i < scourgeGame.getPartySize(); i++ ) {
547			// if not dead
548			if( !( scourgeGame.getPartyMember( i ).getStateMod( 13 ) ) ) {
549				// poisoned
550				scourgeGame.getPartyMember( i ).setStateMod( 6, true );
551				// cursed
552				scourgeGame.getPartyMember( i ).setStateMod( 7, true );
553			}
554		}
555
556		scourgeGame.showTextMessage( _( "You find yourself on a barren plain. The air is thick with moisture and very still. The bleak ground appears to emit a cancerous odor like the smell of death on a roadside cadaver. A sudden rush of despair hangs over you, clouding your senses... Is this the end? The tortured screams of unseen thousands drifts from beyond the nearest door. On this molten landscape filled with hopelessness and horror, even moving around seems to require an extra effort." ) );
557	}
558}
559
560function initChapter9() {
561	i <- 0;
562	if( scourgeGame.getMission().getDungeonDepth() == 0 ) {
563
564		s <- getChapter9Intro();
565		if( s != null ) {
566			for( i = 0; i < scourgeGame.getMission().getCreatureCount(); i++ ) {
567				if( scourgeGame.getMission().getCreature( i ).getMonsterType() == "Positive Energy of Hornaxx" ) {
568					scourgeGame.getMission().getCreature( i ).setIntro( s );
569				} else if( scourgeGame.getMission().getCreature( i ).getMonsterType() == "Negative Energy of Hornaxx" ) {
570					scourgeGame.getMission().getCreature( i ).setIntro( "SQ_RETURN" );
571				}
572			}
573		}
574	}
575}
576
577function getChapter9Intro() {
578	i <- 0;
579	for( i = 0; i < scourgeGame.getPartySize(); i++ ) {
580		key <- encodeKeyForCreature( scourgeGame.getPartyMember( i ), "hornaxx" );
581		value <- scourgeGame.getValue( key );
582		if( value != null ) {
583			numValue <- value.tointeger();
584			if( scourgeGame.getPartyMember( i ).getLevel() > numValue ) {
585				return "SQ_RETURN_TRUE";
586			} else {
587				return "SQ_RETURN_FALSE";
588			}
589		}
590	}
591	return null;
592}
593
594antimagicItems <- [
595  "Boots of antimagic binding",
596  "Antimagic foil hat",
597  "Antimagic chestplate"
598];
599
600antimagicItemLocations <- [
601	256, 1, 8
602];
603
604function initChapter10() {
605	if( scourgeGame.getMission().getDungeonDepth() == 0 ) {
606		scourgeGame.showTextMessage( _( "The ancient walls appear to cave inward as if pushed on by the very roots of the forest from above. A metallic smell cuts the air and the noises echoing from the deep chill your bones. ||A grinding sound wells from beneath your feet as if the wheels of a great machine are turning. Could this be the contdown to Mothrazu's infernal plans? ||And as if that wasn't freeky enough, frequent quakes shake the dungeon..." ) );
607	}
608
609	// poison party members without antimagic binding armor
610	i <- 0;
611	found <- false;
612	equippedItem <- null;
613	t <- 0;
614	for( i = 0; i < scourgeGame.getPartySize(); i++ ) {
615		found = false;
616		for( t = 0; t < antimagicItemLocations.len(); t++ ) {
617			equippedItem = scourgeGame.getPartyMember( i ).getEquippedItem( antimagicItemLocations[ t ] );
618			if( equippedItem != null ) {
619				if( equippedItem.getName() == antimagicItems[ t ] ) {
620					found = true;
621					break;
622				}
623			}
624		}
625		if( !found ) {
626			scourgeGame.printMessage( format( _( "%s feels very ill suddenly." ),
627																				scourgeGame.getPartyMember( i ).getName() ) );
628			scourgeGame.getPartyMember( i ).setStateMod( 6, true );
629		}
630	}
631
632	// start the earthquakes
633	scourgeGame.getMission().setQuakesEnabled( true );
634}
635
636function storePartyLevel() {
637	i <- 0;
638	for( i = 0; i < scourgeGame.getPartySize(); i++ ) {
639		print( "storing for " + i + "\n" );
640		key <- encodeKeyForCreature( scourgeGame.getPartyMember( i ), "hornaxx" );
641		value <- scourgeGame.getValue( key );
642		if( value == null ) {
643			print( "Storing level for " + scourgeGame.getPartyMember( i ).getName() + "\n" );
644			scourgeGame.setValue( key, scourgeGame.getPartyMember( i ).getLevel().tostring() );
645		}
646	}
647}
648
649function assignAntimagicItems() {
650	i <- 0;
651	t <- 0;
652	b <- false;
653	for( i = 0; i < scourgeGame.getPartySize(); i++ ) {
654		key <- encodeKeyForCreature( scourgeGame.getPartyMember( i ), "hornaxx-antimagic" );
655		value <- scourgeGame.getValue( key );
656		if( value == null ) {
657			// Assign items.
658			// The first player gets more more if not all party positions are filled in.
659			n <- 1;
660			if( i == 0 ) n = n + ( 4 - scourgeGame.getPartySize() );
661			r <- 0;
662			for( r = 0; r < n; r++ ) {
663				scourgeGame.getPartyMember( i ).addToBackpackByName( antimagicItems[ t++ ] );
664				if( t >= antimagicItems.len() ) t = 0;
665			}
666			scourgeGame.setValue( key, "true" );
667			b = true;
668		}
669	}
670	if( b ) {
671		scourgeGame.getMission().setCompleted( true );
672	}
673}
674
675function _( s ) {
676	r <- scourgeGame.getTranslatedString( s );
677	return r;
678}
679
680function noop( s ) {
681	return s;
682}
683
684function initChapter11() {
685	if( scourgeGame.getMission().getDungeonDepth() == 0 ) {
686		scourgeGame.showTextMessage( _( "A baleful wind blows bringing the scent of slow vegetative decay. Off in the distance you glance a mighty tree, standing in the center of a barren plane of ashen stone.||No other plants dare intrude upon its territory and no animal life stirs near its accursed branches.||Above, clouds darken the sky as if to signal the long awaited fulfillment of a pending doom." ) );
687
688		// Add creature for spawn of arcanex (need in order to converse w. tree)
689		// This has to be done each time the map is entered b/c npc-s aren't saved with the map.
690		//print( "Adding creature: count=" + scourgeGame.getMission().getCreatureCount() );
691		scourgeGame.getMission().addCreature( 5, 5, 0, "Spawn of Arcanex" );
692		scourgeGame.getMission().setMapConfig( "/maps/tree" );
693	}
694}
695
696function initChapter12() {
697	if( scourgeGame.getMission().getDungeonDepth() == 0 ) {
698
699		scourgeGame.getMission().setMapEffect( 312, 446, 1, // map location
700		                                       "EFFECT_SMOKE",  												// effect
701		                                       1, 1, 																	// base size
702		                                       0,																			// delay
703		                                       true,																	// forever
704		                                       0, 0, 0, 														// offset
705		                                       0.2, 0.2, 0.5 														// color
706																					);
707		scourgeGame.getMission().setMapEffect( 317, 438, 1, // map location
708				                                       "EFFECT_SMOKE",  												// effect
709				                                       1, 1, 																	// base size
710				                                       0,																			// delay
711				                                       true,																	// forever
712				                                       0, 0, 0, 														// offset
713				                                       0.2, 0.2, 0.5 														// color
714																							);
715		scourgeGame.getMission().setMapEffect( 319, 455, 1, // map location
716				                                       "EFFECT_SMOKE",  												// effect
717				                                       1, 1, 																	// base size
718				                                       0,																			// delay
719				                                       true,																	// forever
720				                                       0, 0, 0, 														// offset
721				                                       0.2, 0.2, 0.5 														// color
722																							);
723		scourgeGame.getMission().setMapEffect( 331, 455, 1, // map location
724				                                       "EFFECT_SMOKE",  												// effect
725				                                       1, 1, 																	// base size
726				                                       0,																			// delay
727				                                       true,																	// forever
728				                                       0, 0, 0, 														// offset
729				                                       0.2, 0.2, 0.5 														// color
730																							);
731		scourgeGame.getMission().setMapEffect( 330, 438, 1, // map location
732				                                       "EFFECT_SMOKE",  												// effect
733				                                       1, 1, 																	// base size
734				                                       0,																			// delay
735				                                       true,																	// forever
736				                                       0, 0, 0, 														// offset
737				                                       0.2, 0.2, 0.5 														// color
738																							);
739
740
741		// reset some creatures
742		karzul <- findCreatureByType( "Karzul Agmordexu" );
743		if( karzul != null ) {
744			while( karzul != null ) {
745				karzul.remove();
746				karzul = findCreatureByType( "Karzul Agmordexu" );
747			}
748			karzul <- scourgeGame.getMission().addCreature( 320, 449, 0, "Karzul Agmordexu" );
749			karzul.setNpc( false ); // karzul attacks
750
751			if( scourgeGame.getValue( "guardians_summoned" ) == "true" ) {
752				norill <- findCreatureByType( "Norill" );
753				while( norill != null ) {
754					norill.remove();
755					norill = findCreatureByType( "Norill" );
756				}
757				scourgeGame.getMission().addCreature( 338, 454, 0, "Norill" );
758
759				sarrez <- findCreatureByType( "Sarrez" );
760				while( sarrez != null ) {
761					sarrez.remove();
762					sarrez = findCreatureByType( "Sarrez" );
763				}
764				scourgeGame.getMission().addCreature( 305,454, 0, "Sarrez" );
765
766				rolan <- findCreatureByType( "Rolan" );
767				while( rolan != null ) {
768					rolan.remove();
769					rolan = findCreatureByType( "Rolan" );
770				}
771				scourgeGame.getMission().addCreature( 332,416, 0, "Rolan" );
772
773				scourgeGame.setWeather( WEATHER_RAIN | WEATHER_THUNDER );
774
775				scourgeGame.showTextMessage( _( "Under the pale sky like the blackened husk of a burned tree stands the demon. He calmly awaits your charge fully aware of its futility.||But a red streak lines the mountain tops to the east... is it dawn? Or is it a sign of hope from the gods? Looking around you notice you are no longer alone on the charred battlefield. Three tall warriors in archaic clothing appear as if from nowhere. The tallest one - their leader? - silently bows his head to you.||After this briefest of courtesies, he turns to face Karzul with a steely resolve." ) );
776			}
777		}
778	} else if( scourgeGame.getMission().getDungeonDepth() == 2 ) {
779		//print( "chapter 12 map\n" );
780		scourgeGame.getMission().setMapEffect( 296, 264, 2, // map location
781		                                       "EFFECT_SMOKE",  												// effect
782		                                       3, 3, 																	// base size
783		                                       0,																			// delay
784		                                       true,																	// forever
785		                                       0, 0, 0, 														// offset
786		                                       0.3, 0.7, 0.3 														// color
787																					);
788		scourgeGame.getMission().setMapEffect( 326, 264, 2, // map location
789				                                       "EFFECT_SMOKE",  												// effect
790				                                       3, 3, 																	// base size
791				                                       0,																			// delay
792				                                       true,																	// forever
793				                                       0, 0, 0, 														// offset
794				                                       0.7, 0.3, 0.3 														// color
795																							);
796		scourgeGame.getMission().setMapEffect( 311, 271, 2, // map location
797						                                       "EFFECT_SMOKE",  												// effect
798						                                       3, 3, 																	// base size
799						                                       0,																			// delay
800						                                       true,																	// forever
801						                                       0, 0, 0, 														// offset
802						                                       0.3, 0.3, 0.7 														// color
803																									);
804		scourgeGame.getMission().setMapEffect( 296, 278, 2, // map location
805						                                       "EFFECT_SMOKE",  												// effect
806						                                       3, 3, 																	// base size
807						                                       0,																			// delay
808						                                       true,																	// forever
809						                                       0, 0, 0, 														// offset
810						                                       0.3, 0.7, 0.7 														// color
811																									);
812		scourgeGame.getMission().setMapEffect( 326, 279, 2, // map location
813						                                       "EFFECT_SMOKE",  												// effect
814						                                       3, 3, 																	// base size
815						                                       0,																			// delay
816						                                       true,																	// forever
817						                                       0, 0, 0, 														// offset
818						                                       0.7, 0.3, 0.7 														// color
819																									);
820
821		// the nightwards depart
822		if( scourgeGame.getValue( "guardians_summoned" ) == "true" ) {
823			creature <- null;
824			i <- 0;
825			for( i = 0; i < scourgeGame.getMission().getCreatureCount(); i++ ) {
826				creature = scourgeGame.getMission().getCreature( i );
827				if( creature.isNpc() ) {
828					creature.setVisible( false );
829				}
830			}
831		}
832
833	}
834}
835
836function outdoorMapCompleted( mapName ) {
837	print( "Customizing map: " + mapName + "\n" );
838	if( scourgeGame.getMission().getChapter() == 10 && scourgeGame.getMission().isStoryLineMission() ) {
839
840		// level the area in the center
841		x <- 0;
842		y <- 0;
843		for( x = 250; x < 350; x++ ) {
844			for( y = 250; y < 350; y++ ) {
845				scourgeGame.getMission().setHeightMap( x, y, 3.0 );
846				scourgeGame.getMission().removeMapPosition( x, y, 0 );
847				// color the ground
848			}
849		}
850
851		// add the tree of emeril
852		scourgeGame.getMission().setMapPosition( 312, 288, 0, "TREE-EMERIL-TRUNK" );
853		scourgeGame.getMission().setMapPosition( 300, 300, 12, "TREE-EMERIL-TOP" );
854
855		// add decoration around tree
856
857		// link to cfg file (contains conversations)
858
859
860	}
861}
862
863function handleTreeOfEmeril() {
864	hasCronostar <- false;
865	i <- 0;
866	t <- 0;
867	item <- null;
868	print( "Looking for cronostar...\n" );
869	for( i = 0; hasCronostar == false && i < scourgeGame.getPartySize(); i++ ) {
870		print( "\tparty member=" + i + "...\n" );
871		for( t = 0; t < scourgeGame.getPartyMember( i ).getBackpackContentsCount(); t++ ) {
872			item = scourgeGame.getPartyMember( i ).getBackpackItem( t );
873			if( item.getName() == "Cronostar" ) {
874				hasCronostar = true;
875				break;
876			}
877		}
878	}
879	print( "found it? " + ( hasCronostar ? "true" : "false" ) + "\n" );
880	if( hasCronostar ) {
881		for( i = 0; i < scourgeGame.getMission().getCreatureCount(); i++ ) {
882			print( "\tcreature=" + scourgeGame.getMission().getCreature(i).getMonsterType() + "\n" );
883			if( scourgeGame.getMission().getCreature(i).getMonsterType() == "Spawn of Arcanex" ) {
884				print( "\t\tstarting conversation!\n" );
885				scourgeGame.getMission().getCreature(i).startConversation();
886				break;
887			}
888		}
889	}
890}
891