Description of the modules¶
In the sections below you can find a detailed description of the theory behind the algorithms implemented in the Gazebo plugins developed for the UUV Simulator.
Underwater object plugin¶
This plugin is the core of the simulation of underwater vehicles. It contains an implementation of Fossen’s equation of motion for underwater vehicles (see [5] or [6] for more details). For underwater robots, oarine robotics in general, the SNAME [1] convention is used to represent poses and velocities using the North East Down (NED) reference frame convention.
Theoretical background¶
The nomenclature for position, orientation and velocity vectors can be seen in the table below [2].
| Forces and moments | Velocities | Position and orientation | ||
|---|---|---|---|---|
| Motion in the x-direction | Surge | X | u | x |
| Motion in the y-direction | Sway | Y | v | y |
| Motion in the z-direction | Heave | Z | w | z |
| Rotation about the x-axis | Roll | K | p | \(\phi\) |
| Rotation about the y-axis | Pitch | M | q | \(\theta\) |
| Rotation about the z-axis | Yaw | N | r | \(\psi\) |
The pose of the vehicle is represented by the vector \(\boldsymbol{\eta} = (x, y, z, \phi, \theta, \psi)^T\) and the velocity (represented in the BODY frame) is written as \(\boldsymbol{\nu} = (u, v, w, p, q, r)^T\). The transformation between BODY and NED frame is achieved through a Jacobian matrix as follows (see [6] for more details).
To describe the motion of an object in the water, the influence of the fluid surrounding the object has to be considered. The most common method used is Fossen’s equation of motion, where you consider:
- Added-mass: with the acceleration of a body in a fluid, the surrounding volume of fluid will be accelerated during the motion.
- Hydrodynamic damping: damping has several sources of contribution, such as skin friction, viscous damping. It is usually divided into linear and quadratic damping for simplification.
- Hydrostatic forces: for an object in the water, buoyancy is a new force component has to be taken into account. It is dependent on the object’s volume and the fluid’s density. The resulting force between buoyancy and gravitational forces is known as restoring force. When an object has positive buoyancy for instance, it means that the buoyany force is greater than the gravitational force, and the object will float unless other forces are acting on the body.
Added mass and some damping contributions are in reality frequency dependent, but for underwater robotics it is often considered that these coefficients are constant. The equation of motion [5] can be written as follows
In this equation,
- \(\mathbf{M}_{RB}\) and \(\mathbf{C}_{RB}\) represent respectively the rigid-body inertial and Coriolis and centripetal matrices.
- \(\mathbf{M}_{A}\) is the constant added-mass matrix and \(\mathbf{C}_A(\boldsymbol{\nu})\) the resulting added-mass Coriolis and centripetal matrix.
- \(\mathbf{D}(\boldsymbol{\nu})\) represents linear and quadratic damping components.
- \(\mathbf{g}(\boldsymbol{\eta})\) is the vector of restoring forces.
- \(\mathbf{\tau}\) is the generalized force vector for external and control forces and moments.
Implementation aspects¶
Gazebo offers a wide range of physics engines to rigid-body dynamics simulation already and an API that can be used to write plugins to extend the functionalities of the simulator. In general, packages that offer some extension on the dynamics simulation for a certain type of entity have to implement model plugins that will be called by Gazebo at each iteration to generate the necessary forces and torques.
Since the rigid-body dynamics and contact forces are simulated by Gazebo already, what is left to be computed are the hydrodynamic and hydrostatic forces and moments described in the previous section, namely
where \(\mathbf{g}_b(\boldsymbol{\eta})\) stands for the buoyancy force vector represented in the BODY frame, since the gravitational force is already computed by Gazebo.
Added-mass forces and moments
Damping forces and moments
The damping matrices are implemented here following the equation described by [11].
Buoyancy forces and moments
The buoyancy force is the easiest implementation of this list. There are two options that can be setup in order to compute the buoyancy force. For underwater vehicles, once the center of buoyancy \(\mathbf{r}_b\), fluid density, volume are provided, the buoyancy force vector is generated and applied on the vehicle’s center of buoyancy with respect to the Gazebo’s inertial frame as
Note
The \(\mathbf{f}_b\) vector is generated in the plugin with respect to Gazebo’s inertial frame, which follows the ENU (East North Up) convention, not NED.
Plugin’s URDF description¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <gazebo>
<plugin name="uuv_plugin" filename="libunderwater_object_ros_plugin.so">
<fluid_density>1028.0</fluid_density>
<flow_velocity_topic>hydrodynamics/current_velocity</flow_velocity_topic>
<debug>$(arg debug)</debug>
<link name="${namespace}/base_link">
<neutrally_buoyant>0</neutrally_buoyant>
<volume>0</volume>
<box>
<width>0</width>
<length>0</length>
<height>0</height>
</box>
<center_of_buoyancy>0 0 0</center_of_buoyancy>
<hydrodynamic_model>
<type>fossen</type>
<added_mass>
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
</added_mass>
<linear_damping>
0 0 0 0 0 0
</linear_damping>
<linear_damping_forward_speed>
0 0 0 0 0 0
</linear_damping_forward_speed>
<quadratic_damping>
0 0 0 0 0 0
</quadratic_damping>
</hydrodynamic_model>
</link>
</plugin>
</gazebo>
|
Thruster plugin¶
Theoretical background¶
The computation of the dynamics of the thrust force generated by the thruster is a very complex task. Many sources have already addressed it, such as [4] and [13], but it is difficult to determine one single method to describe it, and the parametrization of the equation, regardless which one you choose, will need the identification of the equation’s parameters through Bollard tests.
The plugin implemented can be described by two modules:
- the dynamics module describes the dynamics of the thruster’s rotor
- and the conversion function, which describes the steady-state relationship between the rotor’s angular velocity and the thrust force output
These two models can be configured using the options below according to the model of thruster being used in the vehicle. The thruster plugin


@* * Copyright 2020 HM Revenue & Customs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *@ @import config.AppConfig @(pageTitle: String, heading: String, message: String, sidebarLink: Option[Html]=None, gaEventId:Option[String]=None)(implicit messages: Messages, appConfig: AppConfig) @mainContent = {
@message
} } @analyticsAdditionalJs = { @gaEventId.fold(HtmlFormat.empty){ eventId => ga('send', { hitType: 'event', eventCategory: 'content - view', eventAction: 'TaxHistory', eventLabel: '@eventId'}); } } @views.html.main_template(title = pageTitle, bodyClasses = None, sidebarLinks =None, contentHeader = None, analyticsAdditionalJs = Some(analyticsAdditionalJs)){ @mainContent @sidebarLink.map{link=>@link} }


{% extends 'base.html' %} {% load staticfiles %} {% block main_content %}
TeleGif is based off the icebreaker game, “Telephone”, where an original message is passed along a chain of players through whispers, and is entertaining through the often very distorted message at the end.
TeleGif is a spin-off of the game that relies on Giphy’s magnificent random-ness when selecting gifs instead of whispers to distort messages.


(Deprecated API)
(Deprecated API)
Includes enterprise licensing and support
The Google Maps API for Flash now contains support for three-dimensional (3D) maps. 3D maps using the Maps API for Flash are shown using a realistic perspective much like that used within Google Earth.
Use of 3D maps within the Google Maps API for Flash requires use of a
new object, the Map3D
object, which is used in place of the
standard Map
object. Rendering of 3D maps is supported on both
Flash 9 and Flash 10 players. However, due to geometry support, use of Flash
10 is recommended as it results in faster rendering. Consult
Compiling for Flash 9/10 for more information about
how to compile your applications for Flash 9 or 10.
This guide illustrates how to use the Map3D
object to create
a 3D map, how to manipulate the view of the map, and how to transform
coordinates on the map into screen coordinates (and vice versa). Developers
should make sure they understand the concepts documented in the tutorials of
this documentation set before reading this section.
Support for three-dimensional maps is new. We encourage you to post questions and feature requests to the Google Maps API for Flash forum.
Although applications built using Google Maps API for Flash will work in both Flash 9 and Flash 10 players, 3D maps take advantage of advanced geometry support in Flash 10, so we recommend that you build your applications for that player.
Note that if you build your applications for Flash 10, but use no code specific to Flash 10, your applications will still work in both Flash 9 or Flash 10, and provide a much better user experience on Flash 10 capable browsers. However, if you do use specific classes/methods for Flash 10, browsers using Flash 9 will throw an error using your applications; in those cases, you may wish to compile separate versions of your application for Flash 9 and for Flash 10.
To compile for Flash 10, you may require a later version of the Flex SDK which contains SWC files for the Flash 10 player. For the latest Flex SDK links, consults Adobe's Flex downloads page.
You will also need to update the Flex SDK or Flex Builder to reference the Flash 10 player SWC appropriately. Consult Adobe's instructions for updating the Flex SDK and Flex Builder to compile for Flash 10. Note that you may need to exit Flex Builder and restart for the settings to take effect.
To add 3D capabilities to your map, you simply need to make the following changes to your code:
com.google.maps.Map3D
,
com.google.maps.View
, and com.google.maps.geom.Attitude
classes.Map
object, extend a Map3D
object.MAP_PREINITIALIZE
event, set the map's
view to VIEWMODE_PERSPECTIVE
The following code displays a map of New York City, but uses a 3D map and initializes it with an oblique angle:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <maps:Map3D xmlns:maps="com.google.maps.*" mapevent_mappreinitialize="onMapPreinitialize(event)" id="map" width="100%" height="100%" key="your_api_key" sensor="true_or_false"/> <mx:Script> <![CDATA[ import com.google.maps.LatLng; import com.google.maps.Map3D; import com.google.maps.MapEvent; import com.google.maps.MapOptions; import com.google.maps.MapType; import com.google.maps.View; import com.google.maps.geom.Attitude; private function onMapPreinitialize(event:MapEvent):void { var myMapOptions:MapOptions = new MapOptions(); myMapOptions.zoom = 12; myMapOptions.center = new LatLng(40.756054, -73.986951); myMapOptions.mapType = MapType.NORMAL_MAP_TYPE; myMapOptions.viewMode = View.VIEWMODE_PERSPECTIVE; myMapOptions.attitude = new Attitude(20,30,0); map.setInitOptions(myMapOptions); } ]]> </mx:Script> </mx:Application>
View example (Map3DSimple.html)
View Source (Map3DSimple.mxml)
Note that you will need an API key (either within the hosted HTML file or the SWF itself) to get this map to display.
In the above example, we defined an Attitude for the map.
The attitude is a value of type com.google.maps.geom.Attitude
which defines the angles of incidence for the map, as seen from the viewer's
perspective (which we call the "camera").
These angles of incidence are three values:
yaw
defines the "direction" of the camera with respect
to north. A yaw
of 0
corresponds to looking
straight north.pitch
defines the angle of incidence of the camera with
respect to the map's horizon. By default, a pitch
of zero
points corresponds to looking straight down at the map.roll
defines the angle of incidence of the camera with
respect to its "footing" (if you are standing, this would be the floor
below you). By altering roll, you can place yourself upside down, for
example.
Pitch, yaw, and roll are commonly used within aeronautical (and astronautical) engineering to define the orientation of an aircraft and its flight dynamics. For more information, see the Wikipedia article on Flight Dynamics.
In the code sample below, you can independently set either yaw
or
pitch
. Note that pitch
values greater than 70 degrees
are not allowed (the value will be floored to 70) and the roll
value
is currently ignored within Attitude
declarations.
View example (Map3DAttitude.html)
View Source (Map3DAttitude.mxml)
You can manipulate the 3D map using the same keyboard controls as you use on Google Earth and within the Maps API. Clicking and dragging moves the map in the direction being dragged, as you would expect. When dragging the map while holding down an optional modifier key, however, you can alter the attitude of the map:
A full list of keyboard controls is available within the Google Earth User Guide.
You may also add a NavigationControl
that contains panning,
zooming and attitude sub-controls. Adding such a control is recommended as the
control automatically includes appropriate controls for manipulating 3D maps. To
do so, declare a handler for the MAP_READY
event and add the
control:
import com.google.maps.controls.MapTypeControl; import com.google.maps.controls.NavigationControl; ... // Modify the map declaration to add a mapevent_mapready event <maps:Map3D xmlns:maps="com.google.maps.*" mapevent_mappreinitialize="onMapPreinitialize(event)" mapevent_mapready="onMapReady(event)" id="map" width="100%" height="100%" key="your_api_key" sensor="true_or_false"/> ... // Within the handler, add the control private function onMapReady(event:MapEvent):void { map.addControl(new MapTypeControl()); map.addControl(new NavigationControl()); }
In the previous code sample, notice that the distance between two points on
the screen is greater towards the top of the screen than towards the bottom.
This behavior is due to the map being initialized with a view of
VIEWMODE_PERSPECTIVE
. With a
perspective
map, the map is projected on a viewport (the screen) using a virtual
point of reference in front of the screen (the camera). These three
components (the map, the viewport and the camera) form a perspective on the
viewport which gives the illusion of depth perception to the map. (See
illustration below.)
The Map3D
object contains a view
property
which indicates what sort of view the 3D map should exhibit. This view is a
class of type com.google.maps.View
which may contain the
following values:
VIEWMODE_2D
A standard two-dimensional map. Use this view
if you want the 3D map to exhibit the same look and feel as a standard
map.VIEWMODE_PERSPECTIVE
constructs a map view using a 3D
perspective based on a "camera's" point of reference. Perspectives are
only possible within the Google Maps API for Flash for maps looking
"ahead." It is not possible to alter a map so that it "looks behind."VIEWMODE_ORTHOGONAL
creates a map with oblique angles but
no perspective. Effectively, all distances are equidistant along the
longitudinal and latitudinal axes of the map.The view VIEWMODE_PERSPECTIVE
view is graphically intensive
and may work slower on Flash 9, which does not have as advanced geometry
support as Flash 10. For that reason, you may also use
VIEWMODE_ORTHOGONAL
which displays a map at a oblique angle, but does
not add perspective. (Effectively, this map eliminates perspective by
placing the camera at an infinite distance to the viewport and map.)
The following code displays the same map of New York City as above but
uses a VIEWMODE_ORTHOGONAL
map:
import com.google.maps.LatLng; import com.google.maps.Map3D; import com.google.maps.MapEvent; import com.google.maps.MapOptions; import com.google.maps.MapType; import com.google.maps.View; import com.google.maps.controls.MapTypeControl; import com.google.maps.controls.NavigationControl; import com.google.maps.geom.Attitude; private function onMapPreinitialize(event:MapEvent):void { var myMapOptions:MapOptions = new MapOptions(); myMapOptions.zoom = 12; myMapOptions.center = new LatLng(40.756054, -73.986951); myMapOptions.mapType = MapType.NORMAL_MAP_TYPE; myMapOptions.viewMode = View.VIEWMODE_ORTHOGONAL; myMapOptions.attitude = new Attitude(20,30,0); map.setInitOptions(myMapOptions); } private function onMapReady(event:MapEvent):void { map.addControl(new NavigationControl()); map.addControl(new MapTypeControl()); }
View example (Map3DOrthogonalSimple.html)
View Source (Map3DOrthogonal.mxml)
Notice that when you manipulate the map, you change its attitude but all distances are still equidistant on the map. At lower levels of obliqueness, this may not matter but at higher angles, it will be noticeable.
The Map3D
class provides a special flyTo()
method for changing the location, zoom level and Attitude
of
the map through animation much like that used in Google Earth. The
flyTo()
method takes the following parameters:
LatLng
at which to position the map's centerAttitude
to position the cameraNote that if you pass 0
for the time value that you will get
an instantaneous transition. Otherwise, the API will attempt a smooth
animated transition from the current location to the new location.
The following code geocodes submitted locations and positions the map to
the new location using the flyTo()
method with a 5 second
animation.
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:Panel title="Google Maps 3D FlyTo Demo" width="100%" height="100%"> <mx:VBox width="100%" height="100%"> <mx:HBox width="100%" height="25"> <mx:Label text="Enter address: "/> <mx:TextInput id="address" text="Coney Island, Brooklyn, NY" dropShadowColor="0x000000" enter="doFlyTo(event);" /> <mx:Button id="submitButton" label="Search" click="doFlyTo(event);" /> </mx:HBox> <maps:Map3D xmlns:maps="com.google.maps.*" mapevent_mappreinitialize="onMapPreinitialize(event)" mapevent_mapready="onMapReady(event)" id="map" key="YOUR_API_KEY" sensor="true_or_false" width="100%" height="100%" /> </mx:VBox> </mx:Panel> <mx:Script> <![CDATA[ import com.google.maps.LatLng; import com.google.maps.Map3D; import com.google.maps.MapEvent; import com.google.maps.MapMouseEvent; import com.google.maps.services.GeocodingEvent; import com.google.maps.services.ClientGeocoder; import com.google.maps.overlays.Marker; import com.google.maps.InfoWindowOptions; import com.google.maps.MapOptions; import com.google.maps.MapType; import com.google.maps.View; import com.google.maps.controls.NavigationControl; import com.google.maps.geom.Attitude; import mx.controls.Alert; private function onMapPreinitialize(event:MapEvent):void { var myMapOptions:MapOptions = new MapOptions; myMapOptions.zoom = 12; myMapOptions.center = new LatLng(40.756054, -73.986951); myMapOptions.mapType = MapType.PHYSICAL_MAP_TYPE; myMapOptions.viewMode = View.VIEWMODE_PERSPECTIVE; myMapOptions.attitude = new Attitude(20,30,0); this.map.setInitOptions(myMapOptions); } private function onMapReady(event:MapEvent):void { this.map.addControl(new NavigationControl()); } private function doFlyTo(event:Event):void { // Instantiate a Geocoder var geocoder:ClientGeocoder = new ClientGeocoder(); // Add an event listener for a GEOCODING SUCCESS geocoder.addEventListener( GeocodingEvent.GEOCODING_SUCCESS, function(event:GeocodingEvent):void { var placemarks:Array = event.response.placemarks; if (placemarks.length > 0) { map.flyTo(placemarks[0].point,12,new Attitude(20,30,0),3); var marker:Marker = new Marker(placemarks[0].point); marker.addEventListener(MapMouseEvent.CLICK, function (event:MapMouseEvent):void { marker.openInfoWindow(new InfoWindowOptions({content: placemarks[0].address})); }); map.addOverlay(marker); } } ); geocoder.addEventListener( GeocodingEvent.GEOCODING_FAILURE, function(event:GeocodingEvent):void { Alert.show("Geocoding failed"); trace(event); trace(event.status); } ); geocoder.geocode(address.text); } ]]> </mx:Script> </mx:Application>
View example (Map3DFlyTo.html)
Unlike a standard two-dimensional map, a three-dimensional map requires greater understanding of how the map is viewed and placed on the screen. This understanding not only affects the overall view of the map, but how to interact with it and how to translate coordinates from one coordinate system to another.
For a 3D map in the Google Maps API for Flash, the "camera" is the focus of the perspective's origin. In general, you don't need to know the camera's position; you're more interested in the result of the camera' position (the view of the map within the viewport). However, you will need to know how to translate coordinates between what the camera sees on the viewport and what the map exhibits on the map at the oblique angle.
On a two-dimensional map, it is relatively straightforward to translate
between locations on a map (LatLng
values) and locations on the
screen (pixels) because the map is oriented in the same direction in both
cases. For 3D maps, this is no longer the case, so we also supply "world
coordinates" defined as the pixel coordinates of the map if it were placed
at zoom level 0. World coordinates vary between (0,0) and (256,256) as shown
on the diagram below:
Viewport (screen) coordinates are shown in red, while world coordinates are shown in green. Note that world coordinates wrap longitudinally, so that world coordinate (259.999,0) is immediately adjacent to world coordinate (0,0). In the figure above, world coordinate (210,0) is at the right-hand edge of the map; world coordinate (210.001,0) is at the left-hand edge of the map.
The ICamera
interface provides the getTranslationGeometry()
method for converting between these three coordinate systems, useful for placing
three-dimensional objects on the map. For full details, consult the
Maps API for Flash Reference.


Below you can either upload two ontologies as a file or directly paste the ontologies in a textbox and run the matcher.


GAS petitions fisheries ministry to ban importation of Tilapia and combat illegal fishing
The Ghana Aquaculture Stakeholders (GAS) has petitioned the Ministry of Fisheries and Aquaculture Development (MOFAD), to take immediate action to safeguard aquaculture business activities by banning the importation of tilapia and illegal activities on the Volta Lake.
According to the GAS, the increasing illegal activities by some foreign nationals are gradually collapsing the fishing industry which employs many fishers on the Volta Lake.
GAS said its survey has revealed that fish farms in areas around the Volta Lake are currently faced with unprecedented challenges.
GAS stated these when it presented a petition to the MOFAD.
Speaking to Peace News, the Founder of Ghana Aquaculture Stakeholders, Patricia Safo said the government must ensure a comprehensive cleanup of the sector to stop illegal activities that are spreading disease and rapidly depleting the country’s fish reserves.
Patricia Safo added that more than 60% of fish farming along the Volta Lake have collapsed due to such illegal activities on the Volta Lake.
She said hundreds of the youth in the area have also lost their jobs hence the need for government intervention.
Receiving the petition the Deputy Minister of Fisheries and Aquaculture Development, Kingsley Ato Cudjoe assured the GAS that government will give serious attention to the concerns of GAS.
Hon Ato Cudjoe said upon coming into power from 2017 the NPP government has taken measures to promote aquaculture in the country.
He said government through MOFAD will implement the Aquaculture for Food and Jobs program from 2020 to increase fish production and create more job opportunities for the people.


Popular Areas in perforated back panel for electrical enclosure
Electronic Enclosures | Ice Qube, Inc.
Standup Enclosures; Desktop Enclosures; Electrical Enclosures . Panel-mount or touch screen top monitor door .  Panels & Panel Accessories. Discount Schedule: C2; A2. JIC & Small Enclosure Perforated Panels. Subclass: DS0. Illustration Sheet and .
http://www.cooperindustries.com/content/dam/public/bline/Resources/Library/catalogs/electrical_enclosures/enclosures_and_wireway/Accessories-JICSmallEnclosurePerforatedPanels.pdf
Buy Floor Standing Enclosures Enclosure, floor ... - RS Components
Buy Enclosure, floor standing, 1800x600x400 NSYSM18640P or other Floor Standing . Electrical, Automation & Cables .  Reinforcement frame made up of two perforated uprights with a pitch of 25mm and .
http://uk.rs-online.com/web/p/floor-standing-enclosures/7064903/
Industrial Enclosures, Wall Mounted Enclosure, Electrical ...
Rittal's enclosures offer durable protection for a wide variety of applications, including electrical wiring, in practically any plant floor environment.
http://www.rittal.us/products/index.cfm
Perforated Panels for C3R Series Enclosures (18PP Series ...
Perforated Panels for C3R Series Enclosures 18PP Series. Home / Electrical / Accessories / Panels and Panel Accessories. Restriction of Hazardous .
http://www.hammfg.com/electrical/products/accessories/18pp


Deepika Padukone to turn co-producer for Karan Johar’s next?
by BizAsia CorrespondentAfter a quiet couple of years away from any film project, Deepika Padukone is all set to unleash her new offerings with Kabir Khan’s ’83’ and Meghna Gulzar’s ‘Chhapaak’. It’s also being reported that she will be seen in Shakun Batra’s dark romantic thriller, helmed by Karan Johar.
However, one exciting part of this news is that Padukone will not only be acting in the film but also co-producing it. A source told PinkVilla, “Dippy’s film with Shakun has her playing the central character. She shoulders the film, that is a dark romantic drama, where Siddhant Chaturvedi has been paired opposite her. Karan and Deepika discussed the project and the actress really loved the idea. In fact, she also spoke to Karan and they both agreed to have her on board as a co-producer.”
Keep it with BizAsiaLive.com for more.


Lok Dhaba is a project of the Trivedi Center for Political Data, a research center led by faculty members in the Political Science and Computer Science Departments at Ashoka University.
Lok Dhaba's interface has been developed with open source tools such as R, Shiny, Plotly, Leaflet, data tables and rgdal. Our maps are originally from DataMeet and have been cleaned and treated in-house. The Lok Dhaba software itself is open source under a Apache 2.0 license and is available from our Github page.
The current lead developer for the Lok Dhaba software is Mohit Kumar, who is a Data Scientist and GIS Engineer at TCPD. Much data collection, cleaning, analysis and testing has been carried by out Saloni Bhogale, Basim Nissa and Priyamvada Trivedi. Many students and interns have also contributed to Lok Dhaba.
Past members: Dr. Chinmay Narayan, Rajkamal Singh and Venkat Prasath.
See more about the TCPD team. You can write to us at tcpd-contact@ashoka.edu.in.


Cookie Comets
For the sensitive people in your life
Notes
- Preparation time:
- Cooking time:
- Servings: 33 cookies
- Difficulty: Medium
Ingredients
- ½ cup coconut oil
- ½ cup palm oil shortening
- ¼ cup sugar
- 1¼ cups brown sugar
- 2 cups + 2 tablespoons gluten free flour blend1
- ¼ cup cornstarch
- 1 teaspoon xanthan gum
- 1½ teaspoons kosher salt
- 1 teaspoon baking soda
- 1 whole egg (use egg replacer)
- 1 egg yolk (use egg replacer)
- 3 tablespoons coconut milk
- 1½ teaspoons vanilla extract
- 12 ounces semisweet chocolate chips2
- (Optional) ½ cup chopped pecans
Instructions
In a medium bowl, sift together the flour, cornstarch, xanthan gum, salt and baking soda. Set aside.
Whisk coconut oil, palm oil shortening, sugar, and brown sugar together in a large mixing bowl. Once combined whisk vigorously for 3 minutes to cream the coconut oil, shortening, and sugar.
Add the whole egg and egg yolk substitutes, coconut milk and vanilla extract to the creamed sugar and oil. Mix until well combined. Slowly incorporate the flour mixture until thoroughly combined. Add the chocolate chips and stir to combine.
 Cover with plastic wrap to prevent moisture loss. Chill the dough in the refrigerator until firm, at least 2 hours and up to 8 hours.
Preheat the oven to 375° F.
Bake for 14 minutes, rotating the pans after 7 minutes for even baking. Remove from the oven and cool the cookies on the pans for 2 minutes. Move the cookies to a wire rack and cool completely. After cooking, store cookies in an airtight container.
- Recommended: Pamela's All Purpose Gluten Free Flour ↩
- Recommended: Enjoy Life Semi Sweet Chocolate Chips ↩


Lectures
Monday, Wednesday and Friday 11:15AM-12:05PM MM 312.Tuesday 8:00AM-9:15AM MM 203 (Quizzes, Exercises, Tests).
Literature
Essential Calculus. James Stewart.Course Contents
Limits and continuity, derivatives and applications, the definite integral and applications.Chapters 1,2,3,4 and 7 from Stewart's book.
Examination and Grading
Tests (50%)
There will be 3 tests. These will be given on Tuesdays and will be announced at least one week in advance. The test with lower score will be dropped and each of the other two remaining will be worth 25% towards the final grade. There will be no make-up tests.Final (30%)
There will be a comprehensive final to be worth 30% and is scheduled for December 8, 11:00AM-1:30PM.Homework and Quizzes (20%)
There will be homework to be handed in every week. The homework will be assigned and completed in WebAssign (http://www.webassign.net/) . The homework posted during each week will be due the Friday of the following week. An accesscode for WebAssign is bundled with the new textbook purchased through the UM Bookstore. To get enrolled in the course in WebAssign you should use the class key: miami 3393 9666There may also be some additional homework problems without any due date but that you should complete in order to train the concepts given in class. Some of these problems could appear in the quizzes, tests and the final. These problems will be assigned after some of the classes and also posted in the web page of the course.
There will be (unannounced) quizzes on some Tuesdays.
Homework and quizzes are equally weighted for the remaining 20% of the grade.
Grading Scale
| Percentage | Grade |
|---|---|
| >=90% | A |
| >=80% | B |
| >=70% | C |
| >=60% | D |
| <60% | F |
Syllabus
This is an approximate schedule of the course containing the syllabus:| Date | Topic |
|---|---|
| Wed 8/25 | Introduction. 1.1 Functions and their representations |
| Fri 8/27 | 1.2 Especial Functions |
| Mon 8/30 | 1.3 The limit of a function |
| Tue 8/31 | |
| Wed 9/01 | 1.4 Calculating limits |
| Fri 9/03 | 1.4 Calculating limits |
| Tue 9/07 | |
| Wed 9/08 | 1.5 Continuity |
| Fri 9/10 | 1.6 Limits involving infinity |
| Mon 9/13 | 2.1 Derivatives and rates of change |
| Tue 9/14 | |
| Wed 9/15 | 2.2 The derivative as a function |
| Fri 9/17 | 2.2 The derivative as a function |
| Mon 9/20 | 2.3 Basic differentiation formulas |
| Tue 9/21 | |
| Wed 9/22 | 2.3 Basic differentiation formulas |
| Fri 9/24 | 2.4 The product and quotients rules |
| Mon 9/27 | 2.5 The chain rule |
| Tue 9/28 | |
| Wed 9/29 | 2.6 Implicit differentiation |
| Fri 10/01 | 2.7 Related rates |
| Mon 10/04 | 2.8 Linear approximations and differentials |
| Tue 10/05 | |
| Wed 10/06 | 3.1 Maximum and minimum values |
| Fri 10/08 | 3.1 Maximum and minimum values |
| Mon 10/11 | 3.2 The mean value theorem |
| Tue 10/12 | |
| Wed 10/13 | 3.3 Derivatives and the shapes of graphs |
| Mon 10/18 | 3.3 Derivatives and the shapes of graphs |
| Tue 10/19 | |
| Wed 10/20 | 3.4 Curve sketching |
| Fri 10/22 | 3.4 Curve sketching |
| Mon 10/25 | 3.5 Optimization problems |
| Tue 10/26 | |
| Wed 10/27 | 3.5 Optimization problems |
| Fri 10/29 | (optional) 3.6 Newton's method |
| Mon 11/01 | 3.7 Antiderivatives |
| Tue 11/02 | |
| Wed 11/03 | 3.7 Antiderivatives |
| Fri 11/05 | 4.1 Areas and distances |
| Mon 11/08 | 4.2 The definite integral |
| Tue 11/09 | |
| Wed 11/10 | 4.3 Evaluating definite integrals |
| Fri 11/12 | 4.4 The fundamental theorem of calculus |
| Mon 11/15 | 4.4 The fundamental theorem of calculus |
| Tue 11/16 | |
| Wed 11/17 | 4.5 The substitution rule |
| Fri 11/19 | 4.5 The substitution rule |
| Mon 11/22 | 7.1 Areas between curves |
| Tue 11/23 | |
| Wed 11/24 | 7.2 Volumes |
| Mon 11/29 | 7.2 Volumes |
| Tue 11/30 | |
| Wed 12/01 | 7.3 Volumes by cylindrical shells |
| Fri 12/03 | (optional) 7.4 Arc length |


dvr
DocumentList - Content Services
Demonstrates multiple Alfresco Content Services components used together to display the files of your Content Services instance:
apps
Process Services
Demonstrates multiple Alfresco Process Services components used together to show your Process Services process and tasks:
view_module
DataTable - Content Services & Process Services
Basic table component:
file_upload
Uploader - Content Services
Basic table uploader component for the Content Services & Process Services:
account_circle
Login - Content Services & Process Services
Login component for the Content Services and Process Services:
extension
Webscript - Content Services
Displays and creates webscripts in your Content Services instance:
local_offer
Tag - Content Services
Displays and adds tags to the node of your Content Services instance:


This component displays what is inside as the prefix icon.
| Name |
Default |
Description |
| tabIndexValue: number |
0 |
Tabindex value given to the preffix icon. |
| onClickPrefix: EventEmitter |
|
This function will be called when the prefix is clicked. |
This component displays what is inside as the suffix icon.
| Name |
Default |
Description |
| tabIndexValue: number |
0 |
Tabindex value given to the suffix icon. |
| onClickSuffix: EventEmitter |
|
This function will be called when the suffix is clicked. |


{% extends 'base.html' %} {% block content %}
Get the contents of pdf, jpg, png files including tabular data using the power of OCR scanning tool


{% extends 'gameserver/base.html' %} {% load gravatar_tags %} {% block main %}
This user has not shared any information.


Models
predicsis.jsSDK.models
| post /models | Models.create() | async |
| post /models | Models.createClassifier() | async |
| get /models | Models.all() | |
| get /models/:id | Models.get() | |
| patch /models/:id | Models.update() | async |
| delete /models/:id | Models.delete() | |
| Wraps all API requests for a learn | Models.learn() | |
| Official documentation is available at: |
Output example:
{ id: "54c25b446170700001a80300", created_at: "2015-01-23T14:31:32.797Z", updated_at: "2015-01-23T14:31:34.060Z", title: "", type: "classifier", user_id: "541b06dc617070006d060000", preparation_rules_set_id: null, job_ids: [ "54c25b446170700001a90300" ], model_variables: [ { name: "Petal Width", level: 0.669445, weight: 0.789933, maximum_a_posteriori: true }, { name: "Sepal Length", level: 0.324718, weight: 0.415522, maximum_a_posteriori: false }, { name: "Petal Length", level: 0.625078, weight: 0.392422, maximum_a_posteriori: false }, { name: "Sepal Width", level: 0.165768, weight: 0.343345, maximum_a_posteriori: false } ] }
Create a new classifier.
Simple shortcut for Models.create() function.
| Param | Type | Details |
|---|---|---|
| preparationRulesSetId | String | See preparation rules documentation |
| Promise | A new classifier |
Learn a model
This function wraps the following requests:
... and each time, waits for job termination!
To do so, what we really use are the following parameters:
Please also note that if your project doesn't have a main_modality
parameter, only univariate
supervised report will be created. If this property is here, we also generate classifier evaluation reports
for train and test datasets.
We also broadcast the following events:
| Param | Type | Details |
|---|---|---|
| project | Object | Instance of a valid Project |
| Object | Instance of a complete Models |


This is a message snippet from the author
Based on the last lecture and the presentations sent this is an example webpage implementing some of the tags taught
list of the content
>>HTML,XML,XHTML >>introduction to html source code >>structure of the HTML page >>HTML tags(Elements & Attributes) >>HTML comments >>text-formatting tags
< html > < head > < title >Sample HTML source code< /title > < meta name="descripition"content="" /> < /head > < body > < /body > < /html >head:Content not displayed on the page mostly meta information
The only thing learnt from tetris is that As errors accumulate and achievements are lost


The username needs to be longer that 4 characters,
and the password needs to be at least 8 characters


| Number | Pizza Name | Crust type | Pizza Size | Toppings | Total amount |
|---|---|---|---|---|---|
Dear
The cost of delivery to
is Ksh. 350.
and the total amount of Pizza is Ksh.
You will be reached through as the number you
submitted.
Thank you for choosing us!
Dear
The total amount of Pizza is Ksh. Thank you for choosing us!


Created at {{ entry.unsafeCreatedTimestamp | date }} by {{ entry.spec.uPortName }} {{ entry.owner }}{{ entry.bounty }} ETH in bountyThis bounty is {{ entry.state }}Description: {{ entry.spec.description }}
{{ entry.acceptedSubmission.spec.uPortName }} {{ entry.acceptedSubmission.owner }}
Created at {{ entry.acceptedSubmission.unsafeCreatedTimestamp | date }}
Created at {{ entry.acceptedSubmission.unsafeCreatedTimestamp | date }}Owner: {{ entry.acceptedSubmission.owner }}Description: {{ entry.acceptedSubmission.spec.description }}
{{ submission.spec.uPortName }} {{ submission.owner }}
Created at {{ submission.unsafeCreatedTimestamp | date }}
Created at {{ submission.unsafeCreatedTimestamp | date }}Owner: {{ submission.owner }}Description: {{ submission.spec.description }}


Oracle NUP Standard
Editor
Oracle is the editor of this metric.
Description
This metric can be used in all environments. It is defined as an individual authorized by you to use the programs which are installed on a single server or multiple servers, regardless of whether the individual is actively using the programs at any given time. A non human operated device will be counted as a named user plus in addition to all individuals authorized to use the programs, if such devices can access the programs. If multiplexing hardware or software (e.g. : a TP monitor or a web server product) is used, this number must be measured at the multiplexing front end. Automated batching of data from computer to computer is permitted. You are responsible for ensuring that the named user plus per processor minimums are maintained for the programs.
Formula
MAX between A and B with :
- A = [∑(P(numberofcores)* P(corefactor))] * minimum number of NUP (default: 25)
- B = total number of current users with access to the Oracle product
Modifiable parameter
Minimum number of NUP per processor
Further details
You can find further details about this metric on the Oracle website here


Computing pairwise mutual information, timing comparison
PMTKneedsStatsToolbox hist3 PMTKslow
requireStatsToolbox loadData('20news_w100'); X = documents'; tic; [mi] = mutualInfoAllPairsDiscrete(X);toc tic; [mi2] = mutualInfoAllPairsMixed(X); toc tic; [mi3] = mutualInfoAllPairsMixed(X, [], 'useSpeedup', false); toc approxeq(mi, mi2) approxeq(mi, mi3)
Elapsed time is 2.793218 seconds. Elapsed time is 2.219286 seconds. Elapsed time is 45.811798 seconds. ans = 1 ans = 1


Menu
Search
About
Contact
Changes
Used Textbooks of Laurier
Clinical Psychology 8th edition
By Timothy J. Trull & Mitchell J. Prinstein
Listings
Course Materials
Listing
Name
Condition of the Textbook
Selling Price Range
Willing to Negotiate?
Email
1
Duyen Nguyen-Ta
Very Good Condition
Bought used from the Laurier Bookstore
Highlighting in it
Top and bottom of spine slightly dented
$80-$100
Yes
<EMAIL_ADDRESS>Buy?


switchMap
?#angular-training
channel in Slack
@Effect() loadItems$ = this.actions$.pipe(
ofType(ActionTypes.Load),
switchMap((action: LoadItemsAction) => this.itemsService
.loadItems(action.payload)
.pipe(
map((items: Item[]) => new LoadItemsSuccessAction(item)),
catchError((err) => Observable.of(new LoadItemsFailureAction(err)))
)
),
);
switchMap
?map
let arr1 = ["it's Sunny in", "", "California"];
arr1.map(x => x.split(" "));
// [["it's","Sunny","in"],[""],["California"]]
arr1.flatMap(x => x.split(" "));
// ["it's","Sunny","in", "", "California"]
Arrays are like Streams
Observables
)switchMap
came from Array's flatMap
mergeMap
switchMap
concatMap
exhaustMap
mergeMap
- When you want to preserve all values of the inner observableswitchMap
- If only one inner observable should be active at a timeconcatMap
- If the order of emission of inner observables is importantexhaustMap
- If the outer observable should be ignored while the inner observable is active


Next: write-char, Previous: terpri, Up: Streams Dictionary
unread-char
character &optional input-stream ⇒ nil
character—a character; must be the last character that was read from input-stream.
input-stream—an input stream designator. The default is standard input.
unread-char places character back onto the front of input-stream so that it will again be the next character in input-stream.
When input-stream is an echo stream, no attempt is made to undo any echoing of the character that might already have been done on input-stream. However, characters placed on input-stream by unread-char are marked in such a way as to inhibit later re-echo by read-char.
It is an error to invoke unread-char twice consecutively on the same stream without an intervening call to read-char (or some other input operation which implicitly reads characters) on that stream.
Invoking peek-char or read-char commits all previous characters. The consequences of invoking unread-char on any character preceding that which is returned by peek-char (including those passed over by peek-char that has a non-nil peek-type) are unspecified. In particular, the consequences of invoking unread-char after peek-char are unspecified.
(with-input-from-string (is "0123") (dotimes (i 6) (let ((c (read-char is))) (if (evenp i) (format t "~&~S ~S~ |> 0 #\0 |> 2 #\1 |> 4 #\2 ⇒ NIL
*standard-input*, *terminal-io*.
peek-char, read-char, Stream Concepts
unread-char is intended to be an efficient mechanism for allowing the Lisp reader and other parsers to perform one-character lookahead in input-stream.
Next: write-char, Previous: terpri, Up: Streams Dictionary


Current Streaming Tasks
Type
Progress
Actions
45% Complete
Kill
There are currently no streaming tasks.


Start Scenario Simulation
The prototype simulation will be restricted to the navigation defined in this scenario. You can disable this simulation by removing the filter in the top toolbar.
Simulate scenario
Go to screen


PART VI. VESSEL IDENTIFICATION NUMBERS
[§200-71] Hull, defined. As used in this part, "hull" means the shell, frame, or body of a vessel, exclusive of masts, yards, sails, riggings, machinery, and equipment. [L 1991, c 272, pt of §2]


/*
* File: attack.cc
* Summary: Methods of the attack class, generalized functions which may
* be overloaded by inheriting classes.
* Written by: Robert Burnham
*/
#include "AppHdr.h"
#include "attack.h"
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <functional>
#include "art-enum.h"
#include "chardump.h"
#include "delay.h"
#include "english.h"
#include "env.h"
#include "exercise.h"
#include "fight.h"
#include "fineff.h"
#include "food.h"
#include "god-conduct.h"
#include "god-passive.h" // passive_t::no_haste
#include "item-name.h"
#include "item-prop.h"
#include "message.h"
#include "mon-behv.h"
#include "mon-clone.h"
#include "mon-death.h"
#include "nearby-danger.h"
#include "pronoun-type.h"
#include "religion.h"
#include "spl-util.h"
#include "state.h"
#include "stepdown.h"
#include "stringutil.h"
#include "transform.h"
#include "xom.h"
/*
**************************************************
* BEGIN PUBLIC FUNCTIONS *
**************************************************
*/
attack::attack(actor *attk, actor *defn, actor *blame)
: attacker(attk), defender(defn), responsible(blame ? blame : attk),
attack_occurred(false), cancel_attack(false), did_hit(false),
needs_message(false), attacker_visible(false), defender_visible(false),
perceived_attack(false), obvious_effect(false), to_hit(0),
damage_done(0), special_damage(0), aux_damage(0), min_delay(0),
final_attack_delay(0), special_damage_flavour(BEAM_NONE),
stab_attempt(false), stab_bonus(0), ev_margin(0), weapon(nullptr),
damage_brand(SPWPN_NORMAL), wpn_skill(SK_UNARMED_COMBAT),
shield(nullptr), art_props(0), unrand_entry(nullptr),
attacker_to_hit_penalty(0), attack_verb("bug"), verb_degree(),
no_damage_message(), special_damage_message(), aux_attack(), aux_verb(),
attacker_armour_tohit_penalty(0), attacker_shield_tohit_penalty(0),
defender_shield(nullptr), fake_chaos_attack(false), simu(false),
aux_source(""), kill_type(KILLED_BY_MONSTER)
{
// No effective code should execute, we'll call init_attack again from
// the child class, since initializing an attack will vary based the within
// type of attack actually being made (melee, ranged, etc.)
}
bool attack::handle_phase_attempted()
{
return true;
}
bool attack::handle_phase_blocked()
{
damage_done = 0;
return true;
}
bool attack::handle_phase_damaged()
{
// We have to check in_bounds() because removed kraken tentacles are
// temporarily returned to existence (without a position) when they
// react to damage.
if (defender->can_bleed()
&& !defender->is_summoned()
&& !defender->submerged()
&& in_bounds(defender->pos())
&& !simu)
{
int blood = damage_done;
if (blood > defender->stat_hp())
blood = defender->stat_hp();
if (blood)
blood_fineff::schedule(defender, defender->pos(), blood);
}
announce_hit();
// Inflict stored damage
damage_done = inflict_damage(damage_done);
// TODO: Unify these, added here so we can get rid of player_attack
if (attacker->is_player())
{
if (damage_done)
player_exercise_combat_skills();
}
else
{
if (!mons_attack_effects())
return false;
}
// It's okay if a monster took lethal damage, but we should stop
// the combat if it was already reset (e.g. a spectral weapon that
// took damage and then noticed that its caster is gone).
return defender->is_player() || !invalid_monster(defender->as_monster());
}
bool attack::handle_phase_killed()
{
monster* mon = defender->as_monster();
if (!invalid_monster(mon))
monster_die(*mon, attacker);
return true;
}
bool attack::handle_phase_end()
{
// This may invalidate both the attacker and defender.
fire_final_effects();
return true;
}
/**
* Calculate the to-hit for an attacker
*
* @param random If false, calculate average to-hit deterministically.
*/
int attack::calc_to_hit(bool random)
{
int mhit = attacker->is_player() ?
15 + (you.dex() / 2)
: calc_mon_to_hit_base();
#ifdef DEBUG_DIAGNOSTICS
const int base_hit = mhit;
#endif
// This if statement is temporary, it should be removed when the
// implementation of a more universal (and elegant) to-hit calculation
// is designed. The actual code is copied from the old mons_to_hit and
// player_to_hit methods.
if (attacker->is_player())
{
// fighting contribution
mhit += maybe_random_div(you.skill(SK_FIGHTING, 100), 100, random);
// weapon skill contribution
if (using_weapon())
{
if (wpn_skill != SK_FIGHTING)
{
if (you.skill(wpn_skill) < 1 && player_in_a_dangerous_place())
xom_is_stimulated(10); // Xom thinks that is mildly amusing.
mhit += maybe_random_div(you.skill(wpn_skill, 100), 100,
random);
}
}
else if (you.form_uses_xl())
mhit += maybe_random_div(you.experience_level * 100, 100, random);
else
{
// Claws give a slight bonus to accuracy when active
mhit += (you.get_mutation_level(MUT_CLAWS) > 0
&& wpn_skill == SK_UNARMED_COMBAT) ? 4 : 2;
mhit += maybe_random_div(you.skill(wpn_skill, 100), 100,
random);
}
// weapon bonus contribution
if (using_weapon())
{
if (weapon->base_type == OBJ_WEAPONS)
{
mhit += weapon->plus;
mhit += property(*weapon, PWPN_HIT);
}
else if (weapon->base_type == OBJ_STAVES)
mhit += property(*weapon, PWPN_HIT);
}
// slaying bonus
mhit += slaying_bonus(wpn_skill == SK_THROWING
|| (weapon && is_range_weapon(*weapon)
&& using_weapon()));
// hunger penalty
if (apply_starvation_penalties())
mhit -= 3;
// armour penalty
mhit -= (attacker_armour_tohit_penalty + attacker_shield_tohit_penalty);
// vertigo penalty
if (you.duration[DUR_VERTIGO])
mhit -= 5;
// mutation
if (you.get_mutation_level(MUT_EYEBALLS))
mhit += 2 * you.get_mutation_level(MUT_EYEBALLS) + 1;
// hit roll
mhit = maybe_random2(mhit, random);
}
else // Monster to-hit.
{
if (using_weapon())
mhit += weapon->plus + property(*weapon, PWPN_HIT);
const int jewellery = attacker->as_monster()->inv[MSLOT_JEWELLERY];
if (jewellery != NON_ITEM
&& mitm[jewellery].is_type(OBJ_JEWELLERY, RING_SLAYING))
{
mhit += mitm[jewellery].plus;
}
mhit += attacker->scan_artefacts(ARTP_SLAYING);
}
// Penalties for both players and monsters:
mhit -= 5 * attacker->inaccuracy();
if (attacker->confused())
mhit -= 5;
if (using_weapon()
&& (is_unrandom_artefact(*weapon, UNRAND_WOE)
|| is_unrandom_artefact(*weapon, UNRAND_SNIPER)))
{
return AUTOMATIC_HIT;
}
// If no defender, we're calculating to-hit for debug-display
// purposes, so don't drop down to defender code below
if (defender == nullptr)
return mhit;
if (!defender->visible_to(attacker))
if (attacker->is_player())
mhit -= 6;
else
mhit = mhit * 65 / 100;
else
{
// This can only help if you're visible!
const int how_transparent = you.get_mutation_level(MUT_TRANSLUCENT_SKIN);
if (defender->is_player() && how_transparent)
mhit -= 2 * how_transparent;
if (defender->backlit(false))
mhit += 2 + random2(8);
else if (!attacker->nightvision()
&& defender->umbra())
mhit -= 2 + random2(4);
}
// Don't delay doing this roll until test_hit().
if (!attacker->is_player())
mhit = random2(mhit + 1);
dprf(DIAG_COMBAT, "%s: Base to-hit: %d, Final to-hit: %d",
attacker->name(DESC_PLAIN).c_str(),
base_hit, mhit);
return mhit;
}
/* Returns an actor's name
*
* Takes into account actor visibility/invisibility and the type of description
* to be used (capitalization, possessiveness, etc.)
*/
string attack::actor_name(const actor *a, description_level_type desc,
bool actor_visible)
{
return actor_visible ? a->name(desc) : anon_name(desc);
}
/* Returns an actor's pronoun
*
* Takes into account actor visibility
*/
string attack::actor_pronoun(const actor *a, pronoun_type pron,
bool actor_visible)
{
return actor_visible ? a->pronoun(pron) : anon_pronoun(pron);
}
/* Returns an anonymous actor's name
*
* Given the actor visible or invisible, returns the
* appropriate possessive pronoun.
*/
string attack::anon_name(description_level_type desc)
{
switch (desc)
{
case DESC_NONE:
return "";
case DESC_YOUR:
case DESC_ITS:
return "something's";
case DESC_THE:
case DESC_A:
case DESC_PLAIN:
default:
return "something";
}
}
/* Returns an anonymous actor's pronoun
*
* Given invisibility (whether out of LOS or just invisible), returns the
* appropriate possessive, inflexive, capitalised pronoun.
*/
string attack::anon_pronoun(pronoun_type pron)
{
return decline_pronoun(GENDER_NEUTER, pron);
}
/* Initializes an attack, setting up base variables and values
*
* Does not make any changes to any actors, items, or the environment,
* in case the attack is cancelled or otherwise fails. Only initializations
* that are universal to all types of attacks should go into this method,
* any initialization properties that are specific to one attack or another
* should go into their respective init_attack.
*
* Although this method will get overloaded by the derived class, we are
* calling it from attack::attack(), before the overloading has taken place.
*/
void attack::init_attack(skill_type unarmed_skill, int attack_number)
{
ASSERT(attacker);
weapon = attacker->weapon(attack_number);
wpn_skill = weapon ? item_attack_skill(*weapon) : unarmed_skill;
if (attacker->is_player() && you.form_uses_xl())
wpn_skill = SK_FIGHTING; // for stabbing, mostly
attacker_armour_tohit_penalty =
div_rand_round(attacker->armour_tohit_penalty(true, 20), 20);
attacker_shield_tohit_penalty =
div_rand_round(attacker->shield_tohit_penalty(true, 20), 20);
to_hit = calc_to_hit(true);
shield = attacker->shield();
defender_shield = defender ? defender->shield() : defender_shield;
if (weapon && weapon->base_type == OBJ_WEAPONS && is_artefact(*weapon))
{
artefact_properties(*weapon, art_props);
if (is_unrandom_artefact(*weapon))
unrand_entry = get_unrand_entry(weapon->unrand_idx);
}
attacker_visible = attacker->observable();
defender_visible = defender && defender->observable();
needs_message = (attacker_visible || defender_visible);
if (attacker->is_monster())
{
mon_attack_def mon_attk = mons_attack_spec(*attacker->as_monster(),
attack_number,
false);
attk_type = mon_attk.type;
attk_flavour = mon_attk.flavour;
// Don't scale damage for YOU_FAULTLESS etc.
if (attacker->get_experience_level() == 0)
attk_damage = mon_attk.damage;
else
{
attk_damage = div_rand_round(mon_attk.damage
* attacker->get_hit_dice(),
attacker->get_experience_level());
}
if (attk_type == AT_WEAP_ONLY)
{
int weap = attacker->as_monster()->inv[MSLOT_WEAPON];
if (weap == NON_ITEM || is_range_weapon(mitm[weap]))
attk_type = AT_NONE;
else
attk_type = AT_HIT;
}
else if (attk_type == AT_TRUNK_SLAP && attacker->type == MONS_SKELETON)
{
// Elephant trunks have no bones inside.
attk_type = AT_NONE;
}
}
else
{
attk_type = AT_HIT;
attk_flavour = AF_PLAIN;
}
}
void attack::alert_defender()
{
// Allow monster attacks to draw the ire of the defender. Player
// attacks are handled elsewhere.
if (perceived_attack
&& defender->is_monster()
&& attacker->is_monster()
&& attacker->alive() && defender->alive()
&& (defender->as_monster()->foe == MHITNOT || one_chance_in(3)))
{
behaviour_event(defender->as_monster(), ME_WHACK, attacker);
}
// If an enemy attacked a friend, set the pet target if it isn't set
// already, but not if sanctuary is in effect (pet target must be
// set explicitly by the player during sanctuary).
if (perceived_attack && attacker->alive()
&& (defender->is_player() || defender->as_monster()->friendly())
&& !attacker->is_player()
&& !crawl_state.game_is_arena()
&& !attacker->as_monster()->wont_attack())
{
if (defender->is_player())
{
interrupt_activity(activity_interrupt::monster_attacks,
attacker->as_monster());
}
if (you.pet_target == MHITNOT && env.sanctuary_time <= 0)
you.pet_target = attacker->mindex();
}
}
bool attack::distortion_affects_defender()
{
enum disto_effect
{
SMALL_DMG,
BIG_DMG,
BANISH,
BLINK,
NONE
};
const disto_effect choice = random_choose_weighted(35, SMALL_DMG,
25, BIG_DMG,
10, BANISH,
20, BLINK,
10, NONE);
if (simu && !(choice == SMALL_DMG || choice == BIG_DMG))
return false;
switch (choice)
{
case SMALL_DMG:
special_damage += 1 + random2avg(7, 2);
// No need to call attack_strength_punctuation here,
// since special damage < 7, so it will always return "."
special_damage_message = make_stringf("Space bends around %s.",
defender_name(false).c_str());
break;
case BIG_DMG:
special_damage += 3 + random2avg(24, 2);
special_damage_message =
make_stringf("Space warps horribly around %s%s",
defender_name(false).c_str(),
attack_strength_punctuation(special_damage).c_str());
break;
case BLINK:
if (defender_visible)
obvious_effect = true;
if (!defender->no_tele(true, false))
blink_fineff::schedule(defender);
break;
case BANISH:
if (defender_visible)
obvious_effect = true;
defender->banish(attacker, attacker->name(DESC_PLAIN, true),
attacker->get_experience_level());
return true;
case NONE:
// Do nothing
break;
}
return false;
}
void attack::antimagic_affects_defender(int pow)
{
obvious_effect =
enchant_actor_with_flavour(defender, nullptr, BEAM_DRAIN_MAGIC, pow);
}
/// Whose skill should be used for a pain-weapon effect?
static actor* _pain_weapon_user(actor* attacker)
{
if (attacker->type != MONS_SPECTRAL_WEAPON)
return attacker;
const mid_t summoner_mid = attacker->as_monster()->summoner;
if (summoner_mid == MID_NOBODY)
return attacker;
actor* summoner = actor_by_mid(attacker->as_monster()->summoner);
if (!summoner || !summoner->alive())
return attacker;
return summoner;
}
void attack::pain_affects_defender()
{
actor* user = _pain_weapon_user(attacker);
if (!one_chance_in(user->skill_rdiv(SK_NECROMANCY) + 1))
{
special_damage += resist_adjust_damage(defender, BEAM_NEG,
random2(1 + user->skill_rdiv(SK_NECROMANCY)));
if (special_damage && defender_visible)
{
special_damage_message =
make_stringf("%s %s in agony%s",
defender->name(DESC_THE).c_str(),
defender->conj_verb("writhe").c_str(),
attack_strength_punctuation(special_damage).c_str());
}
}
}
static bool _is_chaos_polyable(const actor &defender)
{
if (!defender.can_safely_mutate())
return false; // no polymorphing undead
const monster* mon = defender.as_monster();
if (!mon)
return true;
return !mons_is_firewood(*mon) && !mons_immune_magic(*mon);
}
static bool _is_chaos_slowable(const actor &defender)
{
const monster* mon = defender.as_monster();
if (!mon)
return true;
return !mons_is_firewood(*mon) && !mon->is_stationary();
}
struct chaos_effect
{
string name;
int chance;
function<bool(const actor& def)> valid;
beam_type flavour;
function<bool(attack &attack)> misc_effect;
};
static const vector<chaos_effect> chaos_effects = {
{
"clone", 1, [](const actor &d) {
return d.is_monster() && mons_clonable(d.as_monster(), true);
},
BEAM_NONE, [](attack &attack) {
actor &defender = *attack.defender;
ASSERT(defender.is_monster());
monster *clone = clone_mons(defender.as_monster(), true);
if (!clone)
return false;
const bool obvious_effect = you.can_see(defender) && you.can_see(*clone);
if (one_chance_in(3))
clone->attitude = coinflip() ? ATT_FRIENDLY : ATT_NEUTRAL;
// The player shouldn't get new permanent followers from cloning.
if (clone->attitude == ATT_FRIENDLY && !clone->is_summoned())
clone->mark_summoned(6, true, MON_SUMM_CLONE);
// Monsters being cloned is interesting.
xom_is_stimulated(clone->friendly() ? 12 : 25);
return obvious_effect;
},
},
{
"polymorph", 2, _is_chaos_polyable, BEAM_POLYMORPH,
},
{
"shifter", 1, [](const actor &defender)
{
const monster *mon = defender.as_monster();
return _is_chaos_polyable(defender)
&& mon && !mon->is_shapeshifter()
&& defender.holiness() & MH_NATURAL;
},
BEAM_NONE, [](attack &attack) {
monster* mon = attack.defender->as_monster();
ASSERT(_is_chaos_polyable(*attack.defender));
ASSERT(mon);
ASSERT(!mon->is_shapeshifter());
const bool obvious_effect = you.can_see(*attack.defender);
mon->add_ench(one_chance_in(3) ? ENCH_GLOWING_SHAPESHIFTER
: ENCH_SHAPESHIFTER);
// Immediately polymorph monster, just to make the effect obvious.
mon->polymorph();
// Xom loves it if this happens!
const int friend_factor = mon->friendly() ? 1 : 2;
const int glow_factor = mon->has_ench(ENCH_SHAPESHIFTER) ? 1 : 2;
xom_is_stimulated(64 * friend_factor * glow_factor);
return obvious_effect;
},
},
{
"rage", 5, [](const actor &defender) {
return defender.can_go_berserk();
}, BEAM_NONE, [](attack &attack) {
attack.defender->go_berserk(false);
return you.can_see(*attack.defender);
},
},
{ "hasting", 10, _is_chaos_slowable, BEAM_HASTE },
{ "mighting", 10, nullptr, BEAM_MIGHT },
{ "agilitying", 10, nullptr, BEAM_AGILITY },
{ "invisible", 10, nullptr, BEAM_INVISIBILITY, },
{ "slowing", 10, _is_chaos_slowable, BEAM_SLOW },
{
"paralysis", 5, [](const actor &defender) {
return !defender.is_monster()
|| !mons_is_firewood(*defender.as_monster());
}, BEAM_PARALYSIS,
},
{
"petrify", 5, [](const actor &defender) {
return _is_chaos_slowable(defender) && !defender.res_petrify();
}, BEAM_PETRIFY,
},
};
void attack::chaos_affects_defender()
{
ASSERT(defender);
vector<pair<const chaos_effect&, int>> weights;
for (const chaos_effect &effect : chaos_effects)
if (!effect.valid || effect.valid(*defender))
weights.push_back({effect, effect.chance});
const chaos_effect &effect = *random_choose_weighted(weights);
#ifdef NOTE_DEBUG_CHAOS_EFFECTS
take_note(Note(NOTE_MESSAGE, 0, 0, "CHAOS effect: " + effect.name), true);
#endif
if (effect.misc_effect && effect.misc_effect(*this))
obvious_effect = true;
bolt beam;
beam.flavour = effect.flavour;
if (beam.flavour != BEAM_NONE)
{
if (defender->is_player() && have_passive(passive_t::no_haste)
&& beam.flavour == BEAM_HASTE)
{
simple_god_message(" protects you from inadvertent hurry.");
obvious_effect = true;
return;
}
beam.glyph = 0;
beam.range = 0;
beam.colour = BLACK;
beam.effect_known = false;
// Wielded brand is always known, but maybe this was from a call
// to chaos_affect_actor.
beam.effect_wanton = !fake_chaos_attack;
if (using_weapon() && you.can_see(*attacker))
{
beam.name = wep_name(DESC_YOUR);
beam.item = weapon;
}
else
beam.name = atk_name(DESC_THE);
beam.thrower =
(attacker->is_player()) ? KILL_YOU
: attacker->as_monster()->confused_by_you() ? KILL_YOU_CONF
: KILL_MON;
if (beam.thrower == KILL_YOU || attacker->as_monster()->friendly())
beam.attitude = ATT_FRIENDLY;
beam.source_id = attacker->mid;
beam.source = defender->pos();
beam.target = defender->pos();
beam.damage = dice_def(damage_done + special_damage + aux_damage, 1);
beam.ench_power = beam.damage.num;
const bool you_could_see = you.can_see(*defender);
beam.fire();
if (you_could_see)
obvious_effect = beam.obvious_effect;
}
if (!you.can_see(*attacker))
obvious_effect = false; // XXX: VERY dubious!
}
struct chaos_attack_type
{
attack_flavour flavour;
brand_type brand;
int chance;
function<bool(const actor& def)> valid;
};
// Chaos melee attacks randomly choose a brand from here, with brands that
// definitely won't affect the target being invalid. Chaos itself should
// always be a valid option, triggering a more unpredictable chaos_effect
// instead of a normal attack brand when selected.
static const vector<chaos_attack_type> chaos_types = {
{ AF_FIRE, SPWPN_FLAMING, 10,
[](const actor &d) { return !d.is_fiery(); } },
{ AF_COLD, SPWPN_FREEZING, 10,
[](const actor &d) { return !d.is_icy(); } },
{ AF_ELEC, SPWPN_ELECTROCUTION, 10,
nullptr },
{ AF_POISON, SPWPN_VENOM, 10,
[](const actor &d) {
return !(d.holiness() & (MH_UNDEAD | MH_NONLIVING)); } },
{ AF_CHAOTIC, SPWPN_CHAOS, 10,
nullptr },
{ AF_DRAIN_XP, SPWPN_DRAINING, 5,
[](const actor &d) { return bool(d.holiness() & MH_NATURAL); } },
{ AF_VAMPIRIC, SPWPN_VAMPIRISM, 5,
[](const actor &d) {
return !d.is_summoned() && bool(d.holiness() & MH_NATURAL); } },
{ AF_HOLY, SPWPN_HOLY_WRATH, 5,
[](const actor &d) { return d.holy_wrath_susceptible(); } },
{ AF_ANTIMAGIC, SPWPN_ANTIMAGIC, 5,
[](const actor &d) { return d.antimagic_susceptible(); } },
{ AF_CONFUSE, SPWPN_CONFUSE, 2,
[](const actor &d) {
return !(d.holiness() & (MH_NONLIVING | MH_PLANT)); } },
{ AF_DISTORT, SPWPN_DISTORTION, 2,
nullptr },
};
brand_type attack::random_chaos_brand()
{
vector<pair<brand_type, int>> weights;
for (const chaos_attack_type &choice : chaos_types)
if (!choice.valid || choice.valid(*defender))
weights.push_back({choice.brand, choice.chance});
ASSERT(!weights.empty());
brand_type brand = *random_choose_weighted(weights);
#ifdef NOTE_DEBUG_CHAOS_BRAND
string brand_name = "CHAOS brand: ";
switch (brand)
{
case SPWPN_FLAMING: brand_name += "flaming"; break;
case SPWPN_FREEZING: brand_name += "freezing"; break;
case SPWPN_HOLY_WRATH: brand_name += "holy wrath"; break;
case SPWPN_ELECTROCUTION: brand_name += "electrocution"; break;
case SPWPN_VENOM: brand_name += "venom"; break;
case SPWPN_DRAINING: brand_name += "draining"; break;
case SPWPN_DISTORTION: brand_name += "distortion"; break;
case SPWPN_VAMPIRISM: brand_name += "vampirism"; break;
case SPWPN_ANTIMAGIC: brand_name += "antimagic"; break;
case SPWPN_CHAOS: brand_name += "chaos"; break;
case SPWPN_CONFUSE: brand_name += "confusion"; break;
default: brand_name += "BUGGY"; break;
}
// Pretty much duplicated by the chaos effect note,
// which will be much more informative.
if (brand != SPWPN_CHAOS)
take_note(Note(NOTE_MESSAGE, 0, 0, brand_name), true);
#endif
return brand;
}
attack_flavour attack::random_chaos_attack_flavour()
{
vector<pair<attack_flavour, int>> weights;
for (const chaos_attack_type &choice : chaos_types)
if (!choice.valid || choice.valid(*defender))
weights.push_back({choice.flavour, choice.chance});
ASSERT(!weights.empty());
return *random_choose_weighted(weights);
}
void attack::drain_defender()
{
if (defender->is_monster() && coinflip())
return;
if (!(defender->holiness() & MH_NATURAL))
return;
special_damage = resist_adjust_damage(defender, BEAM_NEG,
(1 + random2(damage_done)) / 2);
if (defender->drain_exp(attacker, true, 20 + min(35, damage_done)))
{
if (defender->is_player())
obvious_effect = true;
else if (defender_visible)
{
special_damage_message =
make_stringf(
"%s %s %s%s",
atk_name(DESC_THE).c_str(),
attacker->conj_verb("drain").c_str(),
defender_name(true).c_str(),
attack_strength_punctuation(special_damage).c_str());
}
}
}
void attack::drain_defender_speed()
{
if (needs_message)
{
mprf("%s %s %s vigour!",
atk_name(DESC_THE).c_str(),
attacker->conj_verb("drain").c_str(),
def_name(DESC_ITS).c_str());
}
defender->slow_down(attacker, 5 + random2(7));
}
int attack::inflict_damage(int dam, beam_type flavour, bool clean)
{
if (flavour == NUM_BEAMS)
flavour = special_damage_flavour;
// Auxes temporarily clear damage_brand so we don't need to check
if (damage_brand == SPWPN_REAPING
|| damage_brand == SPWPN_CHAOS && one_chance_in(100))
{
defender->props["reaping_damage"].get_int() += dam;
// With two reapers of different friendliness, the most recent one
// gets the zombie. Too rare a case to care any more.
defender->props["reaper"].get_int() = attacker->mid;
}
return defender->hurt(responsible, dam, flavour, kill_type,
"", aux_source.c_str(), clean);
}
/* If debug, return formatted damage done
*
*/
string attack::debug_damage_number()
{
#ifdef DEBUG_DIAGNOSTICS
return make_stringf(" for %d", damage_done);
#else
return "";
#endif
}
/* Returns standard attack punctuation
*
* Used in player / monster (both primary and aux) attacks
*/
string attack_strength_punctuation(int dmg)
{
if (dmg < HIT_WEAK)
return ".";
else if (dmg < HIT_MED)
return "!";
else if (dmg < HIT_STRONG)
return "!!";
else
return string(3 + (int) log2(dmg / HIT_STRONG), '!');
}
/* Returns evasion adverb
*
*/
string attack::evasion_margin_adverb()
{
return (ev_margin <= -20) ? " completely" :
(ev_margin <= -12) ? "" :
(ev_margin <= -6) ? " closely"
: " barely";
}
void attack::stab_message()
{
defender->props["helpless"] = true;
switch (stab_bonus)
{
case 6: // big melee, monster surrounded/not paying attention
if (coinflip())
{
mprf("You %s %s from a blind spot!",
(you.species == SP_FELID) ? "pounce on" : "strike",
defender->name(DESC_THE).c_str());
}
else
{
mprf("You catch %s momentarily off-guard.",
defender->name(DESC_THE).c_str());
}
break;
case 4: // confused/fleeing
if (!one_chance_in(3))
{
mprf("You catch %s completely off-guard!",
defender->name(DESC_THE).c_str());
}
else
{
mprf("You %s %s from behind!",
(you.species == SP_FELID) ? "pounce on" : "strike",
defender->name(DESC_THE).c_str());
}
break;
case 2:
case 1:
if (you.species == SP_FELID && coinflip())
{
mprf("You pounce on the unaware %s!",
defender->name(DESC_PLAIN).c_str());
break;
}
mprf("%s fails to defend %s.",
defender->name(DESC_THE).c_str(),
defender->pronoun(PRONOUN_REFLEXIVE).c_str());
break;
}
defender->props.erase("helpless");
}
/* Returns the attacker's name
*
* Helper method to easily access the attacker's name
*/
string attack::atk_name(description_level_type desc)
{
return actor_name(attacker, desc, attacker_visible);
}
/* Returns the defender's name
*
* Helper method to easily access the defender's name
*/
string attack::def_name(description_level_type desc)
{
return actor_name(defender, desc, defender_visible);
}
/* Returns the attacking weapon's name
*
* Sets upthe appropriate descriptive level and obtains the name of a weapon
* based on if the attacker is a player or non-player (non-players use a
* plain name and a manually entered pronoun)
*/
string attack::wep_name(description_level_type desc, iflags_t ignre_flags)
{
ASSERT(weapon != nullptr);
if (attacker->is_player())
return weapon->name(desc, false, false, false, false, ignre_flags);
string name;
bool possessive = false;
if (desc == DESC_YOUR)
{
desc = DESC_THE;
possessive = true;
}
if (possessive)
name = apostrophise(atk_name(desc)) + " ";
name += weapon->name(DESC_PLAIN, false, false, false, false, ignre_flags);
return name;
}
/* TODO: Remove this!
* Removing it may not really be practical, in retrospect. Its only used
* below, in calc_elemental_brand_damage, which is called for both frost and
* flame brands for both players and monsters.
*/
string attack::defender_name(bool allow_reflexive)
{
if (allow_reflexive && attacker == defender)
return actor_pronoun(attacker, PRONOUN_REFLEXIVE, attacker_visible);
else
return def_name(DESC_THE);
}
int attack::player_stat_modify_damage(int damage)
{
int dammod = 39;
if (you.strength() > 10)
dammod += (random2(you.strength() - 9) * 2);
else if (you.strength() < 10)
dammod -= (random2(11 - you.strength()) * 3);
damage *= dammod;
damage /= 39;
return damage;
}
int attack::player_apply_weapon_skill(int damage)
{
if (using_weapon())
{
damage *= 2500 + (random2(you.skill(wpn_skill, 100) + 1));
damage /= 2500;
}
return damage;
}
int attack::player_apply_fighting_skill(int damage, bool aux)
{
const int base = aux? 40 : 30;
damage *= base * 100 + (random2(you.skill(SK_FIGHTING, 100) + 1));
damage /= base * 100;
return damage;
}
int attack::player_apply_misc_modifiers(int damage)
{
return damage;
}
/**
* Get the damage bonus from a weapon's enchantment.
*/
int attack::get_weapon_plus()
{
if (weapon->base_type == OBJ_STAVES
#if TAG_MAJOR_VERSION == 34
|| weapon->sub_type == WPN_BLOWGUN
|| weapon->base_type == OBJ_RODS
#endif
)
{
return 0;
}
return weapon->plus;
}
// Slaying and weapon enchantment. Apply this for slaying even if not
// using a weapon to attack.
int attack::player_apply_slaying_bonuses(int damage, bool aux)
{
int damage_plus = 0;
if (!aux && using_weapon())
damage_plus = get_weapon_plus();
if (you.duration[DUR_CORROSION])
damage_plus -= 4 * you.props["corrosion_amount"].get_int();
damage_plus += slaying_bonus(!weapon && wpn_skill == SK_THROWING
|| (weapon && is_range_weapon(*weapon)
&& using_weapon()));
damage += (damage_plus > -1) ? (random2(1 + damage_plus))
: (-random2(1 - damage_plus));
return damage;
}
int attack::player_apply_final_multipliers(int damage)
{
// Can't affect much of anything as a shadow.
if (you.form == transformation::shadow)
damage = div_rand_round(damage, 2);
return damage;
}
void attack::player_exercise_combat_skills()
{
}
/* Returns attacker base unarmed damage
*
* Scales for current mutations and unarmed effects
* TODO: Complete symmetry for base_unarmed damage
* between monsters and players.
*/
int attack::calc_base_unarmed_damage()
{
// Should only get here if we're not wielding something that's a weapon.
// If there's a non-weapon in hand, it has no base damage.
if (weapon)
return 0;
if (!attacker->is_player())
return 0;
int damage = get_form()->get_base_unarmed_damage();
// Claw damage only applies for bare hands.
if (you.has_usable_claws())
damage += you.has_claws() * 2;
if (you.form_uses_xl())
damage += div_rand_round(you.experience_level, 3);
else
damage += you.skill_rdiv(wpn_skill);
if (damage < 0)
damage = 0;
return damage;
}
int attack::calc_damage()
{
if (attacker->is_monster())
{
int damage = 0;
int damage_max = 0;
if (using_weapon() || wpn_skill == SK_THROWING)
{
damage_max = weapon_damage();
damage += random2(damage_max);
int wpn_damage_plus = 0;
if (weapon) // can be 0 for throwing projectiles
wpn_damage_plus = get_weapon_plus();
const int jewellery = attacker->as_monster()->inv[MSLOT_JEWELLERY];
if (jewellery != NON_ITEM
&& mitm[jewellery].is_type(OBJ_JEWELLERY, RING_SLAYING))
{
wpn_damage_plus += mitm[jewellery].plus;
}
wpn_damage_plus += attacker->scan_artefacts(ARTP_SLAYING);
if (wpn_damage_plus >= 0)
damage += random2(wpn_damage_plus);
else
damage -= random2(1 - wpn_damage_plus);
damage -= 1 + random2(3);
}
damage_max += attk_damage;
damage += 1 + random2(attk_damage);
damage = apply_damage_modifiers(damage);
set_attack_verb(damage);
return apply_defender_ac(damage, damage_max);
}
else
{
int potential_damage, damage;
potential_damage = using_weapon() || wpn_skill == SK_THROWING
? weapon_damage() : calc_base_unarmed_damage();
potential_damage = player_stat_modify_damage(potential_damage);
damage = random2(potential_damage+1);
damage = player_apply_weapon_skill(damage);
damage = player_apply_fighting_skill(damage, false);
damage = player_apply_misc_modifiers(damage);
damage = player_apply_slaying_bonuses(damage, false);
damage = player_stab(damage);
// A failed stab may have awakened monsters, but that could have
// caused the defender to cease to exist (spectral weapons with
// missing summoners; or pacified monsters on a stair). FIXME:
// The correct thing to do would be either to delay the call to
// alert_nearby_monsters (currently in player_stab) until later
// in the attack; or to avoid removing monsters in handle_behaviour.
if (!defender->alive())
return 0;
damage = player_apply_final_multipliers(damage);
damage = apply_defender_ac(damage);
damage = max(0, damage);
set_attack_verb(damage);
return damage;
}
return 0;
}
int attack::test_hit(int to_land, int ev, bool randomise_ev)
{
int margin = AUTOMATIC_HIT;
if (randomise_ev)
ev = random2avg(2*ev, 2);
if (to_land >= AUTOMATIC_HIT)
return true;
else if (x_chance_in_y(MIN_HIT_MISS_PERCENTAGE, 100))
margin = (random2(2) ? 1 : -1) * AUTOMATIC_HIT;
else
margin = to_land - ev;
#ifdef DEBUG_DIAGNOSTICS
dprf(DIAG_COMBAT, "to hit: %d; ev: %d; result: %s (%d)",
to_hit, ev, (margin >= 0) ? "hit" : "miss", margin);
#endif
return margin;
}
int attack::apply_defender_ac(int damage, int damage_max) const
{
ASSERT(defender);
int stab_bypass = 0;
if (stab_bonus)
{
stab_bypass = you.skill(wpn_skill, 50) + you.skill(SK_STEALTH, 50);
stab_bypass = random2(div_rand_round(stab_bypass, 100 * stab_bonus));
}
int after_ac = defender->apply_ac(damage, damage_max,
ac_type::normal, stab_bypass);
dprf(DIAG_COMBAT, "AC: att: %s, def: %s, ac: %d, gdr: %d, dam: %d -> %d",
attacker->name(DESC_PLAIN, true).c_str(),
defender->name(DESC_PLAIN, true).c_str(),
defender->armour_class(),
defender->gdr_perc(),
damage,
after_ac);
return after_ac;
}
/* Determine whether a block occurred
*
* No blocks if defender is incapacitated, would be nice to eventually expand
* this method to handle partial blocks as well as full blocks (although this
* would serve as a nerf to shields and - while more realistic - may not be a
* good mechanic for shields.
*
* Returns (block_occurred)
*/
bool attack::attack_shield_blocked(bool verbose)
{
if (defender == attacker)
return false; // You can't block your own attacks!
if (defender->incapacitated())
return false;
const int con_block = random2(attacker->shield_bypass_ability(to_hit)
+ defender->shield_block_penalty());
int pro_block = defender->shield_bonus();
if (!attacker->visible_to(defender))
pro_block /= 3;
dprf(DIAG_COMBAT, "Defender: %s, Pro-block: %d, Con-block: %d",
def_name(DESC_PLAIN).c_str(), pro_block, con_block);
if (pro_block >= con_block)
{
perceived_attack = true;
if (ignores_shield(verbose))
return false;
if (needs_message && verbose)
{
mprf("%s %s %s attack.",
defender_name(false).c_str(),
defender->conj_verb("block").c_str(),
attacker == defender ? "its own"
: atk_name(DESC_ITS).c_str());
}
defender->shield_block_succeeded(attacker);
return true;
}
return false;
}
bool attack::apply_poison_damage_brand()
{
if (!one_chance_in(4))
{
int old_poison;
if (defender->is_player())
old_poison = you.duration[DUR_POISONING];
else
{
old_poison =
(defender->as_monster()->get_ench(ENCH_POISON)).degree;
}
defender->poison(attacker, 6 + random2(8) + random2(damage_done * 3 / 2));
if (defender->is_player()
&& old_poison < you.duration[DUR_POISONING]
|| !defender->is_player()
&& old_poison <
(defender->as_monster()->get_ench(ENCH_POISON)).degree)
{
return true;
}
}
return false;
}
bool attack::apply_damage_brand(const char *what)
{
bool brand_was_known = false;
int brand = 0;
bool ret = false;
if (using_weapon())
brand_was_known = item_brand_known(*weapon);
special_damage = 0;
obvious_effect = false;
brand = damage_brand == SPWPN_CHAOS ? random_chaos_brand() : damage_brand;
if (brand != SPWPN_FLAMING && brand != SPWPN_FREEZING
&& brand != SPWPN_ELECTROCUTION && brand != SPWPN_VAMPIRISM
&& brand != SPWPN_PROTECTION && !defender->alive())
{
// Most brands have no extra effects on just killed enemies, and the
// effect would be often inappropriate.
return false;
}
if (!damage_done
&& (brand == SPWPN_FLAMING || brand == SPWPN_FREEZING
|| brand == SPWPN_HOLY_WRATH || brand == SPWPN_ANTIMAGIC
|| brand == SPWPN_VORPAL || brand == SPWPN_VAMPIRISM))
{
// These brands require some regular damage to function.
return false;
}
switch (brand)
{
case SPWPN_PROTECTION:
if (attacker->is_player())
{
const monster* mon = defender->as_monster();
if (mon && !mons_is_firewood(*mon))
refresh_weapon_protection();
}
break;
case SPWPN_FLAMING:
calc_elemental_brand_damage(BEAM_FIRE,
defender->is_icy() ? "melt" : "burn",
what);
defender->expose_to_element(BEAM_FIRE, 2);
if (defender->is_player())
maybe_melt_player_enchantments(BEAM_FIRE, special_damage);
break;
case SPWPN_FREEZING:
calc_elemental_brand_damage(BEAM_COLD, "freeze", what);
defender->expose_to_element(BEAM_COLD, 2);
break;
case SPWPN_HOLY_WRATH:
if (defender->holy_wrath_susceptible())
special_damage = 1 + (random2(damage_done * 15) / 10);
if (special_damage && defender_visible)
{
special_damage_message =
make_stringf(
"%s %s%s",
defender_name(false).c_str(),
defender->conj_verb("convulse").c_str(),
attack_strength_punctuation(special_damage).c_str());
}
break;
case SPWPN_ELECTROCUTION:
if (defender->res_elec() > 0)
break;
else if (one_chance_in(3))
{
special_damage = 8 + random2(13);
const string punctuation =
attack_strength_punctuation(special_damage);
special_damage_message =
defender->is_player()
? make_stringf("You are electrocuted%s", punctuation.c_str())
: make_stringf("Lightning courses through %s%s",
defender->name(DESC_THE).c_str(),
punctuation.c_str());
special_damage_flavour = BEAM_ELECTRICITY;
defender->expose_to_element(BEAM_ELECTRICITY, 2);
}
break;
case SPWPN_VENOM:
obvious_effect = apply_poison_damage_brand();
break;
case SPWPN_DRAINING:
drain_defender();
break;
case SPWPN_VORPAL:
special_damage = 1 + random2(damage_done) / 3;
// Note: Leaving special_damage_message empty because there isn't one.
break;
case SPWPN_VAMPIRISM:
{
if (!weapon
|| damage_done < 1
|| !actor_is_susceptible_to_vampirism(*defender)
|| attacker->stat_hp() == attacker->stat_maxhp()
|| attacker->is_player() && you.duration[DUR_DEATHS_DOOR]
|| x_chance_in_y(2, 5)
&& !is_unrandom_artefact(*weapon, UNRAND_LEECH))
{
break;
}
int hp_boost = is_unrandom_artefact(*weapon, UNRAND_VAMPIRES_TOOTH)
? damage_done : 1 + random2(damage_done);
hp_boost = resist_adjust_damage(defender, BEAM_NEG, hp_boost);
if (hp_boost)
{
obvious_effect = true;
if (attacker->is_player())
canned_msg(MSG_GAIN_HEALTH);
else if (attacker_visible)
{
if (defender->is_player())
{
mprf("%s draws strength from your wounds!",
attacker->name(DESC_THE).c_str());
}
else
{
mprf("%s is healed.",
attacker->name(DESC_THE).c_str());
}
}
dprf(DIAG_COMBAT, "Vampiric Healing: damage %d, healed %d",
damage_done, hp_boost);
attacker->heal(hp_boost);
}
break;
}
case SPWPN_PAIN:
pain_affects_defender();
break;
case SPWPN_DISTORTION:
ret = distortion_affects_defender();
break;
case SPWPN_CONFUSE:
{
// If a monster with a chaos weapon gets this brand, act like
// AF_CONFUSE.
if (attacker->is_monster())
{
if (one_chance_in(3))
{
defender->confuse(attacker,
1 + random2(3+attacker->get_hit_dice()));
}
break;
}
// Also used for players in fungus form.
if (attacker->is_player()
&& you.form == transformation::fungus
&& !you.duration[DUR_CONFUSING_TOUCH]
&& defender->is_unbreathing())
{
break;
}
// Declaring these just to pass to the enchant function.
bolt beam_temp;
beam_temp.thrower = attacker->is_player() ? KILL_YOU : KILL_MON;
beam_temp.flavour = BEAM_CONFUSION;
beam_temp.source_id = attacker->mid;
if (attacker->is_player() && damage_brand == SPWPN_CONFUSE
&& you.duration[DUR_CONFUSING_TOUCH])
{
beam_temp.ench_power = you.props["confusing touch power"].get_int();
int margin;
if (beam_temp.try_enchant_monster(defender->as_monster(), margin)
== MON_AFFECTED)
{
you.duration[DUR_CONFUSING_TOUCH] = 0;
obvious_effect = false;
}
}
else if (!x_chance_in_y(melee_confuse_chance(defender->get_hit_dice()),
100)
|| defender->as_monster()->check_clarity())
{
beam_temp.apply_enchantment_to_monster(defender->as_monster());
obvious_effect = beam_temp.obvious_effect;
break;
}
break;
}
case SPWPN_CHAOS:
chaos_affects_defender();
break;
case SPWPN_ANTIMAGIC:
antimagic_affects_defender(damage_done * 8);
break;
case SPWPN_ACID:
defender->splash_with_acid(attacker, 3);
break;
default:
if (using_weapon() && is_unrandom_artefact(*weapon, UNRAND_DAMNATION))
attacker->god_conduct(DID_EVIL, 2 + random2(3));
break;
}
if (damage_brand == SPWPN_CHAOS)
{
if (responsible->is_player())
did_god_conduct(DID_CHAOS, 2 + random2(3), brand_was_known);
}
if (!obvious_effect)
obvious_effect = !special_damage_message.empty();
if (needs_message && !special_damage_message.empty())
{
mpr(special_damage_message);
special_damage_message.clear();
}
// Preserve Nessos's brand stacking in a hacky way -- but to be fair, it
// was always a bit of a hack.
if (attacker->type == MONS_NESSOS && weapon && is_range_weapon(*weapon))
apply_poison_damage_brand();
if (special_damage > 0)
inflict_damage(special_damage, special_damage_flavour);
if (obvious_effect && attacker_visible && using_weapon())
{
if (is_artefact(*weapon))
artefact_learn_prop(*weapon, ARTP_BRAND);
else
set_ident_flags(*weapon, ISFLAG_KNOW_TYPE);
}
return ret;
}
/* Calculates special damage, prints appropriate combat text
*
* Applies a particular damage brand to the current attack, the setup and
* calculation of base damage and other effects varies based on the type
* of attack, but the calculation of elemental damage should be consistent.
*/
void attack::calc_elemental_brand_damage(beam_type flavour,
const char *verb,
const char *what)
{
special_damage = resist_adjust_damage(defender, flavour,
random2(damage_done) / 2 + 1);
if (needs_message && special_damage > 0 && verb)
{
// XXX: assumes "what" is singular
special_damage_message = make_stringf(
"%s %s %s%s",
what ? what : atk_name(DESC_THE).c_str(),
what ? conjugate_verb(verb, false).c_str()
: attacker->conj_verb(verb).c_str(),
// Don't allow reflexive if the subject wasn't the attacker.
defender_name(!what).c_str(),
attack_strength_punctuation(special_damage).c_str());
}
}
int attack::player_stab_weapon_bonus(int damage)
{
int stab_skill = you.skill(wpn_skill, 50) + you.skill(SK_STEALTH, 50);
if (player_good_stab())
{
// We might be unarmed if we're using the hood of the Assassin.
const bool extra_good = using_weapon() && weapon->sub_type == WPN_DAGGER;
int bonus = you.dex() * (stab_skill + 100) / (extra_good ? 500 : 1000);
bonus = stepdown_value(bonus, 10, 10, 30, 30);
damage += bonus;
damage *= 10 + div_rand_round(stab_skill, 100 * stab_bonus);
damage /= 10;
}
damage *= 12 + div_rand_round(stab_skill, 100 * stab_bonus);
damage /= 12;
return damage;
}
int attack::player_stab(int damage)
{
// The stabbing message looks better here:
if (stab_attempt)
{
// Construct reasonable message.
stab_message();
practise_stabbing();
}
else
{
stab_bonus = 0;
// Ok.. if you didn't backstab, you wake up the neighborhood.
// I can live with that.
alert_nearby_monsters();
}
if (stab_bonus)
{
// Let's make sure we have some damage to work with...
damage = max(1, damage);
damage = player_stab_weapon_bonus(damage);
}
return damage;
}
/* Check for stab and prepare combat for stab-values
*
* Grant an automatic stab if paralysed or sleeping (with highest damage value)
* stab_bonus is used as the divisor in damage calculations, so lower values
* will yield higher damage. Normal stab chance is (stab_skill + dex + 1 / roll)
* This averages out to about 1/3 chance for a non extended-endgame stabber.
*/
void attack::player_stab_check()
{
// XXX: move into find_stab_type?
if (you.duration[DUR_CLUMSY] || you.confused())
{
stab_attempt = false;
stab_bonus = 0;
return;
}
stab_type st = find_stab_type(&you, *defender);
// Find stab type is also used for displaying information about monsters,
// so upgrade the stab type for !stab and the Spriggan's Knife here
if ((using_weapon()
&& is_unrandom_artefact(*weapon, UNRAND_SPRIGGANS_KNIFE)
|| you.duration[DUR_STABBING] > 0 && coinflip())
&& st != STAB_NO_STAB)
{
st = STAB_SLEEPING;
}
stab_attempt = st != STAB_NO_STAB;
stab_bonus = stab_bonus_denom(st);
// See if we need to roll against dexterity / stabbing.
if (stab_attempt && stab_bonus > 1)
{
stab_attempt = x_chance_in_y(you.skill_rdiv(wpn_skill, 1, 2)
+ you.skill_rdiv(SK_STEALTH, 1, 2)
+ you.dex() + 1,
100);
}
if (stab_attempt)
count_action(CACT_STAB, st);
}
↑ V595 The 'weapon' pointer was utilized before it was verified against nullptr. Check lines: 197, 202.
↑ V1048 The 'beam.colour' variable was assigned the same value.
↑ V648 Priority of the '&&' operation is higher than that of the '||' operation.
↑ V648 Priority of the '&&' operation is higher than that of the '||' operation.
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: attk_type, attk_flavour, attk_damage.


Douglas Yates
Yes, you've arrived at yet another of the millions of personal websites that clutter up the internet these days. This one just covers me and my life so if you have arrived here because I used the words "sex", "girls", "free" and "naked" in this sentence, you're going to be very disappointed.
If you are a friend of mine, please click on every link you see to boost the hit rate and make me feel justified in wasting my time writing this. If not, feel free to leave before you fall asleep.
This website has been completely re-written recently, partly to re-organise the sections, partly to remove the frames which caused problems for all the people that didn't come in at the front page, and partly to show off with CSS. The new design is pure CSS so it works well in any CSS compliant browser which includes Netscape, Opera, and (my personal favourite) Mozilla. Of course, Microsoft Internet Explorer doesn't handle the CSS standards properly so the site won't look exactly the way it's supposed to in MS IE. Older browsers which don't handle CSS properly will show the content, but the navigation bars down the side won't work, instead the navigation text appears at the top of the page so it can still be used, even though it looks crap. There's bound to be a few mistakes here and there so please let me know if you find one.
If you have an older browser and are wondering what you are missing, I suggest you go to Mozilla and get a copy of the browser. It is perfectly CSS compliant, has no adverts, and has some wonderful features to safeguard security unlike the browser from a certain large American software company.


My name is Vennie and I'm a freelance web developer. Throughout the years, I've
been developing and designing projects focusing on industry standards. I specialize in leading-technology
based HTML, CSS, and JavaScript web development. Everything I build uses the latest development principles
and techniques.
 I'm always eager to learn and try new things! Let me know what I can do for you.
Find physical and digital goods in this one of a kind eCommerce website, powered by Wordpress.
Stack: Wordpress | HTML | CSS | Javscript
No Github Repository AvailableBudget your expenses efficiently with this handy application where you can track your expense categories.
Stack: HTML | CSS | Javscript | jQuery | React | Redux | Mongo | NodeJS
Github RepositoryFigure out which number is correct in this variation of the popular Hot Or Cold game. Simply guess a number and the game will tell you if you're hotter or colder each time!
Stack: HTML | CSS | Javscript | jQuery | React
Github RepositoryYour dreams and nightmares are here for safekeeping, and easily viewable whenever you wish to re-live the adventure.
Stack: HTML | CSS | Javscript | jQuery | React | Mongo | NodeJS
Github RepositoryA helpful tool to convert your local currency to any other currencies you choose. Also optionally shows the nearest banks at your location to convert your currencies.
Stack: HTML | CSS | Javscript | jQuery | Fixer API | Google Maps API
Github Repository


Learning Teams
MITx: 6.00.1x
Resources to Help you Succeed
Resources to Help you Succeed
Provided from the course material and modified by me. The bolded links are personally recommended.
Command Line Interface (CLI)
Before you begin
Documentation
- Official Python 3 Documentation - "official"/technical explanation of what a particular function/operator does, examples of correct syntax, what the various libraries are, etc.
Textbooks/Tutorials
Debugging
- Python Tutor - an excellent way to actually visualize how the interpreter actually reads and executes your code
- DiffChecker - compares two sets of text and shows you which lines are different
- Debugging in Python - steps you can take to try to debug your program
Software
Other Q&A
- Stack Overflow - a large Q&A forum for programming concepts (not just Python). Try searching here before you post on the edX forum, and you may find that someone has already answered your question.
More practice problems
- Python Challenge - a series of puzzles you can try to test your Python abilities
- Project Euler - additional programming challenges you can try once your Python knowledge becomes stronger; problems are sorted by increasing difficulty
- Coding Bat - problems you can solve within an online interpreter
- Codewars - improve your skills by training on real code challenges