GUI Scripting: Flashbomb Example

From The DarkMod Wiki
Revision as of 17:32, 4 November 2022 by Geep (talk | contribs) (Add category tag)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

This page is part of a series. See GUI Scripting Language for overview.

Introduction

A flashbomb is an evasive weapon. A player can throw one at enemy AI, hoping that when it explodes, the AI will be momentarily blinded. But if not careful, the player can be likewise blinded briefly, either wholly or in part. That blinding of the player is considered here. The example demonstrates:

  • Using a "gui" spawnarg to select a GUI file, and create a player overlay from it.
  • Use of CallGui with named events.
  • Managing transitions with "if…else" statements and a gui:: parameter.

When a Flashbomb Explodes

Invocation

A thrown flashbomb is a projectile, whose entityDef (namely atdm:projectile_flashbomb in tdm_playertools_flashbomb.def) includes these spawnargs and defaults:

has_result		1
def_result		atdm:result_flashbomb

Those describe a "projectile result" helper entity that gets spawned on impact. In turn, the entityDef for atdm:result_flashbomb includes these spawnargs:

scriptobject		result_flashbomb
gui			guis/playertools/flashbomb.gui

In general, a "projectile result" is handled by C++ code in ProjectileResult.cpp. At the end of complicated processing, there's a call to run (in the case of flashbombs) the script object's function "dud". Flashbomb results are always internally categorized as "duds", not "active", because their explosions invoke no physics or permanent damage.

Within the Script Object's "Dud" Function

This script object, "result_flashbomb" is defined in tdm_weapon_flashbomb_result.script.

Preliminary Calculations to Decide What to Do

Details of this are not shown in the code fragment below.

If the bomb explosion is not within the player's field of view, then no "blinded" overlay is created, just a momentary off-screen light source. But if it is seen and not too far away, then the player is either fully blinded if very close (but not actually hit), or partially blinded otherwise. For partial blindness, the closeness will determine the transparency of the overlay. Specifically, a "transparency" float variable of range 0.0 to 1.0 is calculated.

If "full blind", a particle emitter spawns at the explosion site first, before the overlay is created.

Creating the Blinding Overlay

As the script object code fragment below shows, a full screen overlay is created. If "full blind", the script object calls the GUI's doFullblind event handler. If "half blind", the transparency value is passed to the GUI through gui:: parameter "flashbomb_halfblind_enum". Then doHalfblind is called.

… 
string guiName = getKey("gui"); // has default value "flashbomb.gui"
float overlay = $player1.createOverlay(guiName, 10);
if (fullBlind) {
  $player1.callGui(overlay, "doFullblind");
}
else {
  $player1.setGuiFloat(overlay, "flashbomb_halfblind_enum", transparency);
  $player1.callGui(overlay, "doHalfblind");
}

The GUI

The "flashbomb.gui" file, due to greebo, is shown below (lightly edited). There are two full screen child windowDefs, both hidden at first. Only one will be made visible.

When onNamedEvent doFullblind is called, the overlay becomes opaque white for 1 second, then fades grayly away back to transparent over the next 4 seconds.

When onNamedEvent doHalfblind is called, the transparency affects the initial white opaqueness, which immediately begins its gray fade-away over the next 4 seconds.

The use of "gui::flashbomb_halfblind_enum" as a float, and paired with "if…else" statements, nicely shows how to avoid trying to pass a color vec4 as a gui::parameter into a transition statement.

windowDef Desktop {
   rect      0, 0, 640, 480
   nocursor 1

   windowDef fullBlindEffect {
       rect      0, 0, 640, 480
       backcolor 1, 1, 1, 1
       visible 0
		
       onTime 0 {
           transition backcolor "1 1 1 1" "0 0 0 1" "1000" ;
       }

       onTime 1000 {
           transition backcolor "0 0 0 1" "0 0 0 0" "4000" ;
       }
   }

   windowDef halfBlindEffect {
       rect      0, 0, 640, 480
       backcolor 1, 1, 1, 0.5
       visible 0
	
       onTime 0 {
           if ("gui::flashbomb_halfblind_enum" >= 1) {
               transition backcolor "1 1 1 1" "0 0 0 0" "4000";
           }
           else if ("gui::flashbomb_halfblind_enum" >= 0.8) {
               transition backcolor "1 1 1 0.8" "0 0 0 0" "4000";
           }
           else if ("gui::flashbomb_halfblind_enum" >= 0.6) {
               transition backcolor "1 1 1 0.6" "0 0 0 0" "4000";
           }
           else if ("gui::flashbomb_halfblind_enum" >= 0.4) {
               transition backcolor "1 1 1 0.4" "0 0 0 0" "4000";
           }
           else if ("gui::flashbomb_halfblind_enum" >= 0.2) {
               transition backcolor "1 1 1 0.2" "0 0 0 0" "4000";
           }
           else {
               transition backcolor "1 1 1 0.1" "0 0 0 0" "4000";
           }
       }
   }

   onNamedEvent doFullblind {
       set "fullBlindEffect::visible" "1";
       resetTime "fullBlindEffect" "0";
   }

   onNamedEvent doHalfblind {
       set "halfBlindEffect::visible" "1";
       resetTime "halfBlindEffect" "0";
   }
}